예제 #1
0
 /// <summary>
 /// 获取当前对象中<paramref name="propertyName"/>的值。
 /// </summary>
 /// <param name="model">模型实例。</param>
 /// <param name="propertyName">属性名称。</param>
 /// <returns>返回当前属性的值。</returns>
 protected object GetValue(object model, string propertyName)
 {
     if (propertyName == "$site")
     {
         return((model as IEnumerable).OfType <object>().Count());
     }
     _entityType = _entityType ?? _model.GetEntity(model.GetType());
     return(_entityType?.FindProperty(propertyName)?.Get(model));
 }
예제 #2
0
        /// <summary>
        ///     <para>
        ///         Gets a property with the given name.
        ///     </para>
        ///     <para>
        ///         This API only finds scalar properties and does not find navigation properties. Use
        ///         <see cref="FindNavigation(IEntityType, string)" /> to find a navigation property.
        ///     </para>
        /// </summary>
        /// <param name="entityType"> The entity type. </param>
        /// <param name="name"> The property name. </param>
        /// <returns> The property, or <see langword="null" /> if none is found. </returns>
        public static IProperty GetProperty([NotNull] this IEntityType entityType, [NotNull] string name)
        {
            Check.NotEmpty(name, nameof(name));

            var property = entityType.FindProperty(name);

            if (property == null)
            {
                if (entityType.FindNavigation(name) != null)
                {
                    throw new InvalidOperationException(
                              CoreStrings.PropertyIsNavigation(
                                  name, entityType.DisplayName(),
                                  nameof(EntityEntry.Property), nameof(EntityEntry.Reference), nameof(EntityEntry.Collection)));
                }

                throw new InvalidOperationException(CoreStrings.PropertyNotFound(name, entityType.DisplayName()));
            }

            return(property);
        }
예제 #3
0
        public void Map <TResult>(string name, Expression <Func <TEntity, TResult> > expression)
        {
            if (!(expression.Body is MemberExpression member))
            {
                throw new InvalidOperationException("Expected member expression");
            }

            var property = GetPropertyInfo(member);

            var entityProperty = _entityType.FindProperty(property);

            if (entityProperty == null)
            {
                throw new InvalidOperationException($"The property '{typeof(TEntity).Name}.{property.Name}' is not mapped to entity.");
            }

            Configuration.Mappings.Add(new QueryProperty
            {
                Alias        = name ?? property.Name,
                PropertyInfo = property
            });
        }
예제 #4
0
        /// <summary>
        /// 添加列。
        /// </summary>
        /// <typeparam name="T">属性类型。</typeparam>
        /// <param name="column">列表达式。</param>
        /// <param name="type">字段类型。</param>
        /// <param name="unicode">是否为Unicode编码。</param>
        /// <param name="nullable">是否为空。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <param name="defaultValueSql">默认值SQL字符串。</param>
        /// <param name="computedColumnSql">计算列的SQL字符串。</param>
        /// <param name="action">添加扩展。</param>
        /// <returns>返回操作实例。</returns>
        public virtual CreateTableBuilder <TEntity> Column <T>(
            Expression <Func <TEntity, T> > column,
            string type              = null,
            bool?nullable            = null,
            bool?unicode             = null,
            object defaultValue      = null,
            string defaultValueSql   = null,
            string computedColumnSql = null,
            Action <OperationBuilder <AddColumnOperation> > action = null)
        {
            Check.NotNull(column, nameof(column));

            var property  = _entity.FindProperty(column.GetPropertyAccess().Name);
            var operation = new AddColumnOperation
            {
                Table             = Operation.Table,
                Name              = property.Name,
                ClrType           = property.ClrType,
                ColumnType        = type,
                IsUnicode         = unicode,
                Identity          = property.Identity,
                Seed              = property.Seed,
                Step              = property.Step,
                MaxLength         = property.MaxLength,
                Precision         = property.Precision,
                Scale             = property.Scale,
                IsRowVersion      = property.IsRowVersion,
                IsNullable        = nullable ?? property.IsNullable,
                DefaultValue      = defaultValue,
                DefaultValueSql   = defaultValueSql,
                ComputedColumnSql = computedColumnSql
            };

            Operation.Columns.Add(operation);

            action?.Invoke(new OperationBuilder <AddColumnOperation>(operation));
            return(this);
        }
예제 #5
0
        public void TestMappingComponent()
        {
            // GIVEN a configured application
            Module module = new Module();

            // GIVEN a db context
            module.AddDbContext <TestDbContext>(cfg =>
            {
                var connection = new SqliteConnection($"DataSource=file:TestMapping?mode=memory&cache=shared");
                connection.Open();
                cfg.UseSqlite(connection);
            });

            // GIVEN a configuration
            module.AddDbContextConfiguration <TestDbContext, TestDbContextConfiguration>();

            // WHEN the application is built
            IServiceCollection services = new ServiceCollection();

            module.ConfigureServices(services, null, null);

            IServiceProvider serviceProvider = services.BuildServiceProvider();

            // THEN model configuration is applied
            TestDbContext dbContext = serviceProvider.GetService <TestDbContext>();

            // get the random annotation to check that ConfigureModel was executed.
            IEntityType entityType = dbContext.Model.FindEntityType(typeof(TestDocument));
            IProperty   property   = entityType.FindProperty("Id");

            Assert.Contains(property.GetAnnotations(), a => a.Name == "test annotation");

            // THEN mapper configuration is applied
            ITypeOptions typeOptions = dbContext.GetInfrastructure().GetService <Mapper>().GetTypeOptions(typeof(TestDocument));

            Assert.True(typeOptions.GetMember("Name").IsKey);
        }
        /// <summary>
        ///  Get IProperty configuration of the column used by EF.
        /// </summary>
        /// <param name="context">DbContext</param>
        /// <param name="rootEntityType">Entity type to find property of. In case of owned entity specify parent entity type.</param>
        /// <param name="propertyName">Property of entity. In case of owned entity specify propertyName of format of "NavigationProperty_OwnedEntityProperty".</param>
        /// <returns></returns>
        public static IProperty GetPropertyMapping(this DbContext context, Type rootEntityType, string propertyName)
        {
            string      entityName = TypeExtensions.DisplayName(rootEntityType);
            IEntityType rootEntity = context.Model.FindEntityType(entityName);

            if (rootEntity == null)
            {
                throw new KeyNotFoundException($"Entity {rootEntityType.FullName} is not found in EntityFramework configuration.");
            }

            List <string> propertyNamePath = ReflectionUtility.SplitEfPropertyName(propertyName);
            IProperty     property         = null;

            if (propertyNamePath.Count == 1)
            {
                property = rootEntity.FindProperty(propertyName);
            }
            else if (propertyNamePath.Count == 2)
            {
                string rootEntityNavigationProperty = propertyNamePath[0];
                string ownedEntityProperty          = propertyNamePath[1];

                IEntityType ownedEntity = GetOwnedProperty(context, rootEntity, rootEntityNavigationProperty);
                property = ownedEntity.FindProperty(ownedEntityProperty);
            }
            else
            {
                throw new NotImplementedException("More than 1 level of Entity framework owned entities is not supported.");
            }

            if (property == null)
            {
                throw new KeyNotFoundException($"Property {propertyName} is not found in EntityFramework configuration of {rootEntityType.FullName} type.");
            }

            return(property);
        }
예제 #7
0
        public void Map <TResult>(string name, Expression <Func <TEntity, TResult> > expression)
        {
            if (!(expression.Body is MemberExpression member))
            {
                throw new InvalidOperationException("Expected member expression");
            }

            var info = GetPropertyInfo(member);

            var property = _entityType.FindProperty(info);

            if (property == null)
            {
                throw new InvalidOperationException($"The property '{typeof(TEntity).Name}.{info.Name}' is not mapped to entity.");
            }

            Configuration.Mappings.Add(new QueryProperty
            {
                Name       = name ?? info.Name,
                Type       = info.PropertyType,
                TableName  = Configuration.TableName,
                ColumnName = property.Relational().ColumnName
            });
        }
        public List <Tuple <string, object> > GetInnerValues <T>(IQueryable <T> query, Expression <Func <T, T> > updateFactory, IEntityType entity) where T : class
#endif
        {
#if EF5 || EF6
            // GET mapping
            var mapping = entity.Info.EntityTypeMapping.MappingFragment;
#elif EFCORE
#if NETSTANDARD1_3
            Assembly assembly;

            try
            {
                assembly = Assembly.Load(new AssemblyName("Microsoft.EntityFrameworkCore.SqlServer"));
            }
            catch (Exception ex)
            {
                throw new Exception(ExceptionMessage.BatchOperations_AssemblyNotFound);
            }

            if (assembly == null)
            {
                throw new Exception(ExceptionMessage.BatchOperations_AssemblyNotFound);
            }

            var type = assembly.GetType("Microsoft.EntityFrameworkCore.SqlServerMetadataExtensions");
            var sqlServerPropertyMethod = type.GetMethod("SqlServer", new[] { typeof(IProperty) });
#else
            var assembly           = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName.StartsWith("Microsoft.EntityFrameworkCore.SqlServer"));
            var postgreSqlAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName.StartsWith("Npgsql.EntityFrameworkCore.PostgreSQL", StringComparison.InvariantCulture));

            if (assembly == null && postgreSqlAssembly == null)
            {
                throw new Exception(ExceptionMessage.BatchOperations_AssemblyNotFound);
            }

            MethodInfo sqlServerPropertyMethod = null;

            if (assembly != null)
            {
                var type = assembly.GetType("Microsoft.EntityFrameworkCore.SqlServerMetadataExtensions");
                sqlServerPropertyMethod = type.GetMethod("SqlServer", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(IProperty) }, null);
            }
            else if (postgreSqlAssembly != null)
            {
                var type = postgreSqlAssembly.GetType("Microsoft.EntityFrameworkCore.NpgsqlMetadataExtensions");
                sqlServerPropertyMethod = type.GetMethod("Npgsql", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(IProperty) }, null);
            }
#endif
#endif


            // GET updateFactory command
            var values            = ResolveUpdateFromQueryDictValues(updateFactory);
            var destinationValues = new List <Tuple <string, object> >();

            foreach (var value in values)
            {
#if EF5 || EF6
                // FIND the mapped column
                var column = mapping.ScalarProperties.Find(x => x.Name == value.Key);
                if (column == null)
                {
                    throw new Exception("The destination column could not be found:" + value.Key);
                }
                var columnName = column.ColumnName;
#elif EFCORE
                var property        = entity.FindProperty(value.Key);
                var mappingProperty = sqlServerPropertyMethod.Invoke(null, new[] { property });

                var columnNameProperty = mappingProperty.GetType().GetProperty("ColumnName", BindingFlags.Public | BindingFlags.Instance);
                var columnName         = (string)columnNameProperty.GetValue(mappingProperty);
#endif

                if (value.Value is Expression)
                {
                    // Oops! the value is not resolved yet!
                    ParameterExpression parameterExpression = null;
                    ((Expression)value.Value).Visit((ParameterExpression p) =>
                    {
                        if (p.Type == typeof(T))
                        {
                            parameterExpression = p;
                        }

                        return(p);
                    });

                    // GET the update value by creating a new select command
                    Type[] typeArguments    = { typeof(T), ((Expression)value.Value).Type };
                    var    lambdaExpression = Expression.Lambda(((Expression)value.Value), parameterExpression);
                    var    selectExpression = Expression.Call(
                        typeof(Queryable),
                        "Select",
                        typeArguments,
                        Expression.Constant(query),
                        lambdaExpression);
                    var result = Expression.Lambda(selectExpression).Compile().DynamicInvoke();
#if EF5 || EF6
                    // GET the select command text
                    var commandText = ((IQueryable)result).ToString();

                    // GET the 'value' part
                    var pos = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf("FROM", StringComparison.InvariantCultureIgnoreCase) - 6;

                    var valueSql = commandText.Substring(6, pos);

                    // Add the destination name
                    valueSql = valueSql.Replace("AS [C1]", "");

                    var listReplace = new List <string>()
                    {
                        "[Extent1]",
                        "[Extent2]",
                        "[Extent3]",
                        "[Extent4]",
                        "[Extent5]",
                        "[Extent6]",
                        "[Extent7]",
                        "[Extent8]",
                        "[Extent9]",
                        "[Filter1]",
                        "[Filter2]",
                        "[Filter3]",
                        "[Filter4]",
                        "[Filter5]",
                        "[Filter6]",
                    };

                    // Replace the first value found only!
                    foreach (var itemReplace in listReplace)
                    {
                        if (valueSql.Contains(itemReplace))
                        {
                            valueSql = valueSql.Replace(itemReplace, "B");
                            break;
                        }
                    }
#elif EFCORE
                    RelationalQueryContext queryContext;
                    var command     = ((IQueryable)result).CreateCommand(out queryContext);
                    var commandText = command.CommandText;

#if NETSTANDARD1_3
                    // GET the 'value' part
                    var pos = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) != -1 ?
                              commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.CurrentCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.CurrentCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) - 6 :
                              commandText.IndexOf("FROM", StringComparison.CurrentCultureIgnoreCase) - 6;

                    var valueSql = commandText.Substring(6, pos);
#else
                    // GET the 'value' part
                    var pos = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf("FROM", StringComparison.InvariantCultureIgnoreCase) - 6;

                    var valueSql = commandText.Substring(6, pos);
#endif

                    valueSql = valueSql.Trim();

                    // Add the destination name
                    valueSql = valueSql.Replace("[x]", "B");
                    valueSql = valueSql.Replace("[c]", "B");

                    if (valueSql.Length > 0 &&
                        valueSql[0] == '[' &&
                        valueSql.IndexOf("]", StringComparison.CurrentCultureIgnoreCase) != -1 &&
                        valueSql.IndexOf("]", StringComparison.CurrentCultureIgnoreCase) == valueSql.IndexOf("].[", StringComparison.CurrentCultureIgnoreCase)
                        )
                    {
                        // Could contains [something].[column]

                        // GET the tag
                        var tagToReplace = valueSql.Substring(0, valueSql.IndexOf("]", StringComparison.CurrentCultureIgnoreCase) + 1);
                        valueSql = valueSql.Replace(tagToReplace, "B");
                    }
#endif
                    destinationValues.Add(new Tuple <string, object>(columnName, Expression.Constant(valueSql)));
                }
                else
                {
                    destinationValues.Add(new Tuple <string, object>(columnName, value.Value ?? DBNull.Value));
                }
            }

            return(destinationValues);
        }
        public static IQueryable <TEntity> TreeQuery <TEntity, TKey>(string invariantName, IQueryable <TEntity> query, IEntityType entityType, Expression <Func <TEntity, bool> > startQuery, Expression <Func <TEntity, bool> > whereQuery = null, bool upSearch = false, string orderByProperty = null, int level = 0, bool distinct = false)
            where TEntity : class, IEntity <TKey> //ITreeEntity<TKey>
        //where TKey : struct, IEquatable<TKey>
        {
            var    tableAnnn       = entityType.FindAnnotation("Relational:TableName");
            string tableName       = tableAnnn?.Value.ToString();
            var    anno            = entityType.FindProperty(nameof(ITreeEntity <int> .Pid)).FindAnnotation("Relational:ColumnName");
            string parentFieldName = anno != null?anno.Value.ToString() : nameof(ITreeEntity <int> .Pid);

            var    idAnno    = entityType.FindProperty(nameof(ITreeEntity <int> .Id)).FindAnnotation("Relational:ColumnName");
            string fieldName = idAnno != null?idAnno.Value.ToString() : nameof(ITreeEntity <int> .Id);

            string firstQuery         = query.Where(startQuery).ToSql().Replace(Environment.NewLine, " ");
            string startQueryParament = startQuery.Parameters[0].Name;

            bool   forNpgsql        = IsNpgSql(invariantName);
            string orderByFieldName = null;

            if (!string.IsNullOrEmpty(orderByProperty))
            {
                var orderByAnno = entityType.FindProperty(orderByProperty).FindAnnotation("Relational:ColumnName");
                orderByFieldName = orderByAnno != null?orderByAnno.Value.ToString() : string.Format("\"{0}\"", orderByProperty);

                //forNpgsql = invariantName == "Npgsql.EntityFrameworkCore.PostgreSQL";
            }

            if (forNpgsql && !string.IsNullOrEmpty(orderByFieldName))
            {
                firstQuery = firstQuery.Insert(firstQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), string.Format(", 0 As level, array[\"{0}\".\"{1}\"] as sorder", startQueryParament, orderByFieldName));
            }
            else
            {
                firstQuery = firstQuery.Insert(firstQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), ", 0 As level");
            }

            string secondQuery        = null;
            string thirdQuery         = null;
            string whereQueryParament = tableName.Substring(0, 1).ToLower();

            if (whereQuery == null)
            {
                secondQuery = query.ToSql().Replace(Environment.NewLine, " ");
                thirdQuery  = secondQuery;
                if (forNpgsql && !string.IsNullOrEmpty(orderByFieldName))
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), string.Format(", mytree.level + 1, sorder || \"{0}\".\"{1}\" as sorder", whereQueryParament, orderByFieldName));
                }
                else
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), ", mytree.level + 1");
                }
                if (upSearch)
                {
                    secondQuery += string.Format(" join mytree on \"{0}\".\"{1}\" = \"mytree\".\"{2}\" ", whereQueryParament, fieldName, parentFieldName);
                }
                else
                {
                    secondQuery += string.Format(" join mytree on \"{0}\".\"{1}\" = \"mytree\".\"{2}\" ", whereQueryParament, parentFieldName, fieldName);
                }
            }
            else
            {
                secondQuery        = query.Where(whereQuery).ToSql().Replace(Environment.NewLine, " ");
                thirdQuery         = secondQuery;
                whereQueryParament = startQuery.Parameters[0].Name;
                if (whereQueryParament == startQueryParament)
                {
                    if (forNpgsql)
                    {
                        string forReplace = startQueryParament + ".";
                        whereQueryParament += startQueryParament;
                        string toReplace = whereQueryParament + ".";
                        secondQuery = secondQuery.Replace(forReplace, toReplace);
                        secondQuery = secondQuery.Replace("AS " + startQueryParament, "AS " + whereQueryParament);
                    }
                    else
                    {
                        string forReplace = "\"" + startQueryParament + "\"";
                        whereQueryParament += startQueryParament;
                        string toReplace = "\"" + whereQueryParament + "\"";
                        secondQuery = secondQuery.Replace(forReplace, toReplace);
                    }
                }
                if (forNpgsql)
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), string.Format(", mytree.level + 1, sorder || \"{0}\".\"{1}\" as sorder", whereQueryParament, orderByFieldName));
                }
                else
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), ", mytree.level + 1");
                }
                if (upSearch)
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" WHERE", StringComparison.CurrentCultureIgnoreCase), string.Format(" join mytree on \"{0}\".\"{1}\" = \"mytree\".\"{2}\" ", whereQueryParament, fieldName, parentFieldName));
                }
                else
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" WHERE", StringComparison.CurrentCultureIgnoreCase), string.Format(" join mytree on \"{0}\".\"{1}\" = \"mytree\".\"{2}\" ", whereQueryParament, parentFieldName, fieldName));
                }
            }

            StringBuilder sqlBuilder = new StringBuilder();

            sqlBuilder.Append("with recursive mytree as ( ");
            sqlBuilder.Append(firstQuery);
            sqlBuilder.Append(" union all ");
            sqlBuilder.Append(secondQuery);
            if (!forNpgsql)
            {
                sqlBuilder.Append(" order by level desc");
                if (!string.IsNullOrEmpty(orderByFieldName))
                {
                    //var orderByAnno = entityType.FindProperty(orderByProperty).FindAnnotation("Relational:ColumnName");
                    //string orderByFieldName = orderByAnno!=null? orderByAnno.Value.ToString() : string.Format("\"{0}\"", orderByProperty);
                    sqlBuilder.Append(string.Format(", {0}", orderByFieldName));
                }
            }
            sqlBuilder.Append(") ");

            if (distinct)
            {
                thirdQuery = thirdQuery.Replace("SELECT", "SELECT DISTINCT");
            }
            thirdQuery = thirdQuery.Replace(tableName, "mytree");
            sqlBuilder.Append(thirdQuery);
            if (level > 0)
            {
                if (whereQuery == null)
                {
                    sqlBuilder.Append(" where ");
                }
                else
                {
                    sqlBuilder.Append(" and ");
                }
                sqlBuilder.Append(string.Format("level = {0}", level));
            }

            if (forNpgsql && !string.IsNullOrEmpty(orderByFieldName))
            {
                sqlBuilder.Append(" order by sorder");
            }

            return(query.FromSql(sqlBuilder.ToString()));
        }
        public static IQueryable <TResult> TreeQuery <TEntity, TKey, TResult>(IRepositoryHelper repositoryHelper, IQueryable <TEntity> query, IEntityType entityType, Expression <Func <TEntity, bool> > startQuery, Expression <Func <TEntity, TResult> > selector, Expression <Func <TEntity, bool> > whereQuery = null, bool upSearch = false, string orderByProperty = null, int level = 0, bool distinct = false)
            where TEntity : class, IEntity <TKey> //ITreeEntity<TKey>
            where TResult : class
        //where TKey : struct, IEquatable<TKey>
        {
            var    tableAnnn       = entityType.FindAnnotation("Relational:TableName");
            string tableName       = tableAnnn?.Value.ToString();
            var    anno            = entityType.FindProperty(nameof(ITreeEntity.Pid)).FindAnnotation("Relational:ColumnName");
            string parentFieldName = anno != null?anno.Value.ToString() : nameof(ITreeEntity <int> .Pid);

            var    idAnno    = entityType.FindProperty(nameof(ITreeEntity.Id)).FindAnnotation("Relational:ColumnName");
            string fieldName = idAnno != null?idAnno.Value.ToString() : nameof(ITreeEntity <int> .Id);

            List <DbParameter> dbParameters = new List <DbParameter>();
            SqlWithParameters  firstSqls    = query.Where(startQuery).Select(selector).GetSqlTextWithParement();;

            AddDbParameter(repositoryHelper, dbParameters, firstSqls);


            string firstQuery         = firstSqls.Sql.Replace(Environment.NewLine, " ");
            string startQueryParament = startQuery.Parameters[0].Name;

            bool   forNpgsql        = IsNpgSql(repositoryHelper?.ProviderName);
            string orderByFieldName = null;

            if (!string.IsNullOrEmpty(orderByProperty))
            {
                var orderByAnno = entityType.FindProperty(orderByProperty).FindAnnotation("Relational:ColumnName");
                orderByFieldName = orderByAnno != null?orderByAnno.Value.ToString() : string.Format("\"{0}\"", orderByProperty);

                //forNpgsql = repositoryHelper.ProviderName == "Npgsql.EntityFrameworkCore.PostgreSQL";
            }

            if (forNpgsql && !string.IsNullOrEmpty(orderByFieldName))
            {
                firstQuery = firstQuery.Insert(firstQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), string.Format(", 0 As level, array[\"{0}\".\"{1}\"] as sorder", startQueryParament, orderByFieldName));
            }
            else
            {
                firstQuery = firstQuery.Insert(firstQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), ", 0 As level");
            }

            //with recursive mytree as (
            //select "t"."id", "t"."createtime", "t"."creator", "t"."customdata", "t"."displayname", "t"."group", "t"."icon", "t"."isenabled", "t"."isvisible", "t"."lastmodifytime", "t"."modifier", "t"."name", "t"."pid", "t"."platsupport", "t"."requiredpermissionname", "t"."requiresauthentication", "t"."sindex", "t"."target", "t"."url", 0 as level, ARRAY[t.sindex] as sorder from "menus" as "t" where "t"."pid" is null
            //union all
            //select "tt"."id", "tt"."createtime", "tt"."creator", "tt"."customdata", "tt"."displayname", "tt"."group", "tt"."icon", "tt"."isenabled", "tt"."isvisible", "tt"."lastmodifytime", "tt"."modifier", "tt"."name", "tt"."pid", "tt"."platsupport", "tt"."requiredpermissionname", "tt"."requiresauthentication", "tt"."sindex", "tt"."target", "tt"."url", mytree.level + 1, sorder || tt.sindex as sorder from "menus" as "tt" join mytree on "tt"."pid" = "mytree"."id"  where "tt"."group" = 0
            //)
            //select * from "mytree" as "t" where "t"."group" = 0 ORDER BY SORDER

            string secondQuery        = null;
            string thirdQuery         = null;
            string whereQueryParament = tableName.Substring(0, 1).ToLower();

            if (whereQuery == null)
            {
                secondQuery        = query.Select(selector).ToSql().Replace(Environment.NewLine, " ");
                whereQueryParament = selector.Parameters[0].Name;

                thirdQuery = secondQuery;
                if (forNpgsql && !string.IsNullOrEmpty(orderByFieldName))
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), string.Format(", mytree.level + 1, sorder || \"{0}\".\"{1}\" as sorder", whereQueryParament, orderByFieldName));
                }
                else
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), ", mytree.level + 1");
                }
                if (upSearch)
                {
                    secondQuery += string.Format(" join mytree on \"{0}\".\"{1}\" = \"mytree\".\"{2}\" ", whereQueryParament, fieldName, parentFieldName);
                }
                else
                {
                    secondQuery += string.Format(" join mytree on \"{0}\".\"{1}\" = \"mytree\".\"{2}\" ", whereQueryParament, parentFieldName, fieldName);
                }
            }
            else
            {
                SqlWithParameters secondSqls = secondSqls = query.Where(whereQuery).Select(selector).GetSqlTextWithParement();
                AddDbParameter(repositoryHelper, dbParameters, secondSqls);

                secondQuery        = secondSqls.Sql.Replace(Environment.NewLine, " ");
                thirdQuery         = secondQuery;
                whereQueryParament = whereQuery.Parameters[0].Name;
                if (whereQueryParament == startQueryParament)
                {
                    if (forNpgsql)
                    {
                        string forReplace = startQueryParament + ".";
                        whereQueryParament += startQueryParament;
                        string toReplace = whereQueryParament + ".";
                        secondQuery = secondQuery.Replace(forReplace, toReplace);
                        secondQuery = secondQuery.Replace("AS " + startQueryParament, "AS " + whereQueryParament);
                    }
                    else
                    {
                        string forReplace = "\"" + startQueryParament + "\"";
                        whereQueryParament += startQueryParament;
                        string toReplace = "\"" + whereQueryParament + "\"";
                        secondQuery = secondQuery.Replace(forReplace, toReplace);
                    }
                }
                if (forNpgsql)
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), string.Format(", mytree.level + 1, sorder || \"{0}\".\"{1}\" as sorder", whereQueryParament, orderByFieldName));
                }
                else
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" FROM", StringComparison.CurrentCultureIgnoreCase), ", mytree.level + 1");
                }
                if (upSearch)
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" WHERE", StringComparison.CurrentCultureIgnoreCase), string.Format(" join mytree on \"{0}\".\"{1}\" = \"mytree\".\"{2}\" ", whereQueryParament, fieldName, parentFieldName));
                }
                else
                {
                    secondQuery = secondQuery.Insert(secondQuery.IndexOf(" WHERE", StringComparison.CurrentCultureIgnoreCase), string.Format(" join mytree on \"{0}\".\"{1}\" = \"mytree\".\"{2}\" ", whereQueryParament, parentFieldName, fieldName));
                }
            }

            StringBuilder sqlBuilder = new StringBuilder();

            sqlBuilder.Append("with recursive mytree as ( ");
            sqlBuilder.Append(firstQuery);
            sqlBuilder.Append(" union all ");
            sqlBuilder.Append(secondQuery);
            if (!forNpgsql)
            {
                sqlBuilder.Append(" order by level desc");
                if (!string.IsNullOrEmpty(orderByFieldName))
                {
                    //var orderByAnno = entityType.FindProperty(orderByProperty).FindAnnotation("Relational:ColumnName");
                    //string orderByFieldName = orderByAnno!=null? orderByAnno.Value.ToString() : string.Format("\"{0}\"", orderByProperty);
                    sqlBuilder.Append(string.Format(", {0}", orderByFieldName));
                }
            }
            sqlBuilder.Append(") ");

            if (distinct)
            {
                thirdQuery = thirdQuery.Replace("SELECT", "SELECT DISTINCT");
            }
            thirdQuery = thirdQuery.Replace(tableName, "mytree");
            sqlBuilder.Append(thirdQuery);
            if (level > 0)
            {
                if (whereQuery == null)
                {
                    sqlBuilder.Append(" where ");
                }
                else
                {
                    sqlBuilder.Append(" and ");
                }
                sqlBuilder.Append(string.Format("level = {0}", repositoryHelper.CreateParameterName("level")));
                AddDbParameter(repositoryHelper, dbParameters, "level", level);
            }

            if (forNpgsql && !string.IsNullOrEmpty(orderByFieldName))
            {
                sqlBuilder.Append(" order by sorder");
            }

            //外部where
            //   var pp = db.Database.GetDbConnection().CreateCommand().CreateParameter();
            //    pp.ParameterName ="tid";
            //    pp.Value = 1;

            return(query.Select(selector).FromSql(sqlBuilder.ToString(), dbParameters.ToArray()));
        }
예제 #11
0
        /// <summary>
        ///     Generates code for the annotations on an entity type.
        /// </summary>
        /// <param name="builderName"> The name of the builder variable. </param>
        /// <param name="entityType"> The entity type. </param>
        /// <param name="stringBuilder"> The builder code is added to. </param>
        protected virtual void GenerateEntityTypeAnnotations(
            [NotNull] string builderName,
            [NotNull] IEntityType entityType,
            [NotNull] IndentedStringBuilder stringBuilder)
        {
            Check.NotNull(builderName, nameof(builderName));
            Check.NotNull(entityType, nameof(entityType));
            Check.NotNull(stringBuilder, nameof(stringBuilder));

            var annotations         = entityType.GetAnnotations().ToList();
            var tableNameAnnotation = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.TableName);
            var schemaAnnotation    = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.Schema);

            var nonDefaultName = false;

            if (tableNameAnnotation?.Value != null ||
                entityType.BaseType == null)
            {
                stringBuilder
                .AppendLine()
                .Append(builderName)
                .Append(".")
                .Append(nameof(RelationalEntityTypeBuilderExtensions.ToTable))
                .Append("(")
                .Append(Code.Literal((string)tableNameAnnotation?.Value ?? entityType.Relational().TableName));
                annotations.Remove(tableNameAnnotation);
                nonDefaultName = true;
            }

            if (schemaAnnotation?.Value != null)
            {
                stringBuilder
                .Append(",")
                .Append(Code.Literal((string)schemaAnnotation.Value));
                annotations.Remove(schemaAnnotation);
                nonDefaultName = true;
            }

            if (nonDefaultName)
            {
                stringBuilder.AppendLine(");");
            }

            var discriminatorPropertyAnnotation = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.DiscriminatorProperty);
            var discriminatorValueAnnotation    = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.DiscriminatorValue);

            if ((discriminatorPropertyAnnotation ?? discriminatorValueAnnotation) != null)
            {
                stringBuilder
                .AppendLine()
                .Append(builderName)
                .Append(".")
                .Append(nameof(RelationalEntityTypeBuilderExtensions.HasDiscriminator));

                if (discriminatorPropertyAnnotation?.Value != null)
                {
                    var discriminatorProperty = entityType.FindProperty((string)discriminatorPropertyAnnotation.Value);
                    var propertyClrType       = FindValueConverter(discriminatorProperty)?.ProviderClrType
                                                .MakeNullable(discriminatorProperty.IsNullable)
                                                ?? discriminatorProperty.ClrType;
                    stringBuilder
                    .Append("<")
                    .Append(Code.Reference(propertyClrType))
                    .Append(">(")
                    .Append(Code.Literal((string)discriminatorPropertyAnnotation.Value))
                    .Append(")");
                }
                else
                {
                    stringBuilder
                    .Append("()");
                }

                if (discriminatorValueAnnotation?.Value != null)
                {
                    var value = discriminatorValueAnnotation.Value;
                    var discriminatorProperty = entityType.RootType().Relational().DiscriminatorProperty;
                    if (discriminatorProperty != null)
                    {
                        var valueConverter = FindValueConverter(discriminatorProperty);
                        if (valueConverter != null)
                        {
                            value = valueConverter.ConvertToProvider(value);
                        }
                    }

                    stringBuilder
                    .Append(".")
                    .Append(nameof(DiscriminatorBuilder.HasValue))
                    .Append("(")
                    .Append(Code.UnknownLiteral(value))
                    .Append(")");
                }

                stringBuilder.AppendLine(";");

                annotations.Remove(discriminatorPropertyAnnotation);
                annotations.Remove(discriminatorValueAnnotation);
            }

            IgnoreAnnotations(
                annotations,
                RelationshipDiscoveryConvention.NavigationCandidatesAnnotationName,
                RelationshipDiscoveryConvention.AmbiguousNavigationsAnnotationName,
                InversePropertyAttributeConvention.InverseNavigationsAnnotationName,
                CoreAnnotationNames.NavigationAccessMode,
                CoreAnnotationNames.PropertyAccessMode,
                CoreAnnotationNames.ConstructorBinding);

            if (annotations.Count > 0)
            {
                foreach (var annotation in annotations)
                {
                    stringBuilder
                    .AppendLine()
                    .Append(builderName);

                    GenerateAnnotation(annotation, stringBuilder);

                    stringBuilder
                    .AppendLine(";");
                }
            }
        }
예제 #12
0
        protected virtual void GenerateEntityTypeAnnotations([NotNull] IEntityType entityType, [NotNull] IndentedStringBuilder stringBuilder)
        {
            Check.NotNull(entityType, nameof(entityType));
            Check.NotNull(stringBuilder, nameof(stringBuilder));

            var annotations         = entityType.GetAnnotations().ToList();
            var tableNameAnnotation = annotations.FirstOrDefault(a => a.Name == RelationalFullAnnotationNames.Instance.TableName);
            var schemaAnnotation    = annotations.FirstOrDefault(a => a.Name == RelationalFullAnnotationNames.Instance.Schema);

            stringBuilder
            .AppendLine()
            .AppendLine()
            .Append("b.")
            .Append(nameof(RelationalEntityTypeBuilderExtensions.ToTable))
            .Append("(")
            .Append(_code.Literal((string)tableNameAnnotation?.Value ?? entityType.DisplayName()));
            annotations.Remove(tableNameAnnotation);

            if (schemaAnnotation?.Value != null)
            {
                stringBuilder
                .Append(",")
                .Append(_code.Literal((string)schemaAnnotation.Value));
                annotations.Remove(schemaAnnotation);
            }

            stringBuilder.Append(");");

            var discriminatorPropertyAnnotation = annotations.FirstOrDefault(a => a.Name == RelationalFullAnnotationNames.Instance.DiscriminatorProperty);
            var discriminatorValueAnnotation    = annotations.FirstOrDefault(a => a.Name == RelationalFullAnnotationNames.Instance.DiscriminatorValue);

            if ((discriminatorPropertyAnnotation ?? discriminatorValueAnnotation) != null)
            {
                stringBuilder
                .AppendLine()
                .AppendLine()
                .Append("b.")
                .Append(nameof(RelationalEntityTypeBuilderExtensions.HasDiscriminator));

                if (discriminatorPropertyAnnotation?.Value != null)
                {
                    var propertyClrType = entityType.FindProperty((string)discriminatorPropertyAnnotation.Value)?.ClrType;
                    stringBuilder
                    .Append("<")
                    .Append(_code.Reference(propertyClrType.UnwrapEnumType()))
                    .Append(">(")
                    .Append(_code.UnknownLiteral(discriminatorPropertyAnnotation.Value))
                    .Append(")");
                }
                else
                {
                    stringBuilder
                    .Append("()");
                }

                if (discriminatorValueAnnotation?.Value != null)
                {
                    stringBuilder
                    .Append(".")
                    .Append(nameof(DiscriminatorBuilder.HasValue))
                    .Append("(")
                    .Append(_code.UnknownLiteral(discriminatorValueAnnotation.Value))
                    .Append(")");
                }

                stringBuilder.Append(";");

                annotations.Remove(discriminatorPropertyAnnotation);
                annotations.Remove(discriminatorValueAnnotation);
            }

            if (annotations.Any())
            {
                foreach (var annotation in annotations)
                {
                    stringBuilder
                    .AppendLine()
                    .AppendLine()
                    .Append("b");

                    GenerateAnnotation(annotation, stringBuilder);

                    stringBuilder.Append(";");
                }
            }
        }
 public DocumentSource(IEntityType entityType, CosmosDatabase database)
 {
     _collectionId = entityType.Cosmos().ContainerName;
     _database     = database;
     _idProperty   = entityType.FindProperty(StoreKeyConvention.IdPropertyName);
 }
예제 #14
0
        public List <Tuple <string, object> > GetInnerValues <T>(IQueryable <T> query, Expression <Func <T, T> > updateFactory, IEntityType entity) where T : class
#endif
        {
#if EF5 || EF6
            // GET mapping
            var mapping = entity.Info.EntityTypeMapping.MappingFragment;
#elif EFCORE
#if DNXCORE50
            Assembly assembly;

            try
            {
                assembly = Assembly.Load(new AssemblyName("EntityFramework.MicrosoftSqlServer, Version = 7.0.0.0, Culture = neutral, PublicKeyToken = adb9793829ddae60"));
            }
            catch (Exception)
            {
                throw new Exception("");
            }

            if (assembly == null)
            {
                throw new Exception("");
            }

            var type = assembly.GetType("Microsoft.Data.Entity.SqlServerMetadataExtensions");
            var sqlServerPropertyMethod = type.GetMethod("SqlServer", new[] { typeof(IProperty) });
#else
            var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName == "EntityFramework.MicrosoftSqlServer, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60");

            if (assembly == null)
            {
                throw new Exception("");
            }

            var type = assembly.GetType("Microsoft.Data.Entity.SqlServerMetadataExtensions");
            var sqlServerPropertyMethod = type.GetMethod("SqlServer", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(IProperty) }, null);
#endif
#endif


            // GET updateFactory command
            var values            = ResolveUpdateFromQueryDictValues(updateFactory);
            var destinationValues = new List <Tuple <string, object> >();

            foreach (var value in values)
            {
#if EF5 || EF6
                // FIND the mapped column
                var column = mapping.ScalarProperties.Find(x => x.Name == value.Key);
                if (column == null)
                {
                    throw new Exception("The destination column could not be found:" + value.Key);
                }
                var columnName = column.ColumnName;
#elif EFCORE
                var property        = entity.FindProperty(value.Key);
                var mappingProperty = sqlServerPropertyMethod.Invoke(null, new[] { property });

                var columnNameProperty = mappingProperty.GetType().GetProperty("ColumnName", BindingFlags.Public | BindingFlags.Instance);
                var columnName         = (string)columnNameProperty.GetValue(mappingProperty);
#endif

                if (value.Value is Expression)
                {
                    // Oops! the value is not resolved yet!
                    ParameterExpression parameterExpression = null;
                    ((Expression)value.Value).Visit((ParameterExpression p) =>
                    {
                        if (p.Type == typeof(T))
                        {
                            parameterExpression = p;
                        }

                        return(p);
                    });

                    // GET the update value by creating a new select command
                    Type[] typeArguments    = { typeof(T), ((Expression)value.Value).Type };
                    var    lambdaExpression = Expression.Lambda(((Expression)value.Value), parameterExpression);
                    var    selectExpression = Expression.Call(
                        typeof(Queryable),
                        "Select",
                        typeArguments,
                        Expression.Constant(query),
                        lambdaExpression);
                    var result = Expression.Lambda(selectExpression).Compile().DynamicInvoke();
#if EF5 || EF6
                    // GET the select command text
                    var commandText = ((IQueryable)result).ToString();

                    // GET the 'value' part
                    var valueSql = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                                   commandText.Substring(6, commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6) :
                                   commandText.Substring(6, commandText.IndexOf("FROM", StringComparison.InvariantCultureIgnoreCase) - 6);

                    // Add the destination name
                    valueSql = valueSql.Replace("AS [C1]", "");
                    valueSql = valueSql.Replace("[Extent1]", "B");
#elif EFCORE
                    var command     = ((IQueryable)result).CreateCommand();
                    var commandText = command.CommandText;

#if DNXCORE50
                    // GET the 'value' part
                    var valueSql = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) != -1 ?
                                   commandText.Substring(6, commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) - 6) :
                                   commandText.Substring(6, commandText.IndexOf("FROM", StringComparison.CurrentCultureIgnoreCase) - 6);
#else
                    // GET the 'value' part
                    var valueSql = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                                   commandText.Substring(6, commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6) :
                                   commandText.Substring(6, commandText.IndexOf("FROM", StringComparison.InvariantCultureIgnoreCase) - 6);
#endif

                    // Add the destination name
                    valueSql = valueSql.Replace("[x]", "B");
#endif
                    destinationValues.Add(new Tuple <string, object>(columnName, Expression.Constant(valueSql)));
                }
                else
                {
                    destinationValues.Add(new Tuple <string, object>(columnName, value.Value ?? DBNull.Value));
                }
            }

            return(destinationValues);
        }
예제 #15
0
 // TODO: Consider optimizing/consolidating property/navigation lookup
 // Issue #635
 private static IPropertyBase TryGetPropertyBase(IEntityType entityType, string propertyName)
 => (IPropertyBase)entityType.FindProperty(propertyName)
 ?? entityType.GetNavigations().FirstOrDefault(n => n.Name == propertyName);
예제 #16
0
        private T FindTracked(object[] keyValues, out IReadOnlyList <IProperty> keyProperties)
        {
            var key = _entityType.FindPrimaryKey();

            keyProperties = HarmonyDbSetExtensions.GetPKFieldNames <T>(_entityType).Select(name => _entityType.FindProperty(name)).ToList();

            if (keyProperties.Count != keyValues.Length)
            {
                //we allow partial matches so we dont need to throw here
            }

            for (var i = 0; i < keyValues.Length; i++)
            {
                var valueType    = keyValues[i].GetType();
                var propertyType = keyProperties[i].ClrType;
                if (valueType != propertyType.UnwrapNullableType())
                {
                    throw new ArgumentException(
                              string.Format("key part {0}:{1} was mismatched with {2}:{3}",
                                            i, typeof(T).ShortDisplayName(), valueType.ShortDisplayName(), propertyType.ShortDisplayName()));
                }
            }

            return(_stateManager.TryGetEntry(key, keyValues)?.Entity as T);
        }
 // TODO: Consider optimizing/consolidating property/navigation lookup
 // Issue #635
 private static IPropertyBase TryGetPropertyBase(IEntityType entityType, string propertyName)
     => (IPropertyBase)entityType.FindProperty(propertyName)
        ?? entityType.GetNavigations().FirstOrDefault(n => n.Name == propertyName);
 private static void ValidateConverter(IEntityType entityType, string propertyName, Type converterType = null)
 {
     entityType.FindProperty(propertyName).GetValueConverter().Should().BeOfType(converterType ?? _testEnumConverterType);
 }
        public List <Tuple <string, object> > GetInnerValues <T>(IQueryable <T> query, Expression <Func <T, T> > updateFactory, IEntityType entity) where T : class
#endif
        {
#if EF5 || EF6
            // GET mapping
            var mapping = entity.Info.EntityTypeMapping.MappingFragment;
#elif EFCORE
            var context = query.GetDbContext();

            var databaseCreator = context.Database.GetService <IDatabaseCreator>();

            var assembly     = databaseCreator.GetType().GetTypeInfo().Assembly;
            var assemblyName = assembly.GetName().Name;

            MethodInfo dynamicProviderEntityType = null;
            MethodInfo dynamicProviderProperty   = null;

            bool isSqlServer   = false;
            bool isPostgreSQL  = false;
            bool isMySql       = false;
            bool isMySqlPomelo = false;
            bool isSQLite      = false;

            if (assemblyName == "Microsoft.EntityFrameworkCore.SqlServer")
            {
                isSqlServer = true;
                var type = assembly.GetType("Microsoft.EntityFrameworkCore.SqlServerMetadataExtensions");
                dynamicProviderEntityType = type.GetMethod("SqlServer", new[] { typeof(IEntityType) });
                dynamicProviderProperty   = type.GetMethod("SqlServer", new[] { typeof(IProperty) });
            }
            else if (assemblyName == "Npgsql.EntityFrameworkCore.PostgreSQL")
            {
                isPostgreSQL = true;
                var type = assembly.GetType("Microsoft.EntityFrameworkCore.NpgsqlMetadataExtensions");
                dynamicProviderEntityType = type.GetMethod("Npgsql", new[] { typeof(IEntityType) });
                dynamicProviderProperty   = type.GetMethod("Npgsql", new[] { typeof(IProperty) });
            }
            else if (assemblyName == "MySql.Data.EntityFrameworkCore")
            {
                isMySql = true;
                var type = assembly.GetType("MySQL.Data.EntityFrameworkCore.MySQLMetadataExtensions");
                dynamicProviderEntityType = type.GetMethod("MySQL", new[] { typeof(IEntityType) });
                dynamicProviderProperty   = type.GetMethod("MySQL", new[] { typeof(IProperty) });
            }
            else if (assemblyName == "Pomelo.EntityFrameworkCore.MySql")
            {
                isMySqlPomelo = true;
                var type = assembly.GetType("Microsoft.EntityFrameworkCore.MySqlMetadataExtensions");
                dynamicProviderEntityType = type.GetMethod("MySql", new[] { typeof(IEntityType) });
                dynamicProviderProperty   = type.GetMethod("MySql", new[] { typeof(IProperty) });
            }
            else if (assemblyName == "Microsoft.EntityFrameworkCore.Sqlite")
            {
                isSQLite = true;

                // CHANGE all for this one?
                dynamicProviderEntityType = typeof(RelationalMetadataExtensions).GetMethod("Relational", new[] { typeof(IEntityType) });
                dynamicProviderProperty   = typeof(RelationalMetadataExtensions).GetMethod("Relational", new[] { typeof(IProperty) });
            }
            else
            {
                throw new Exception(string.Format(ExceptionMessage.Unsupported_Provider, assemblyName));
            }
#endif
            // GET updateFactory command
            var values            = ResolveUpdateFromQueryDictValues(updateFactory);
            var destinationValues = new List <Tuple <string, object> >();

            int valueI = -1;
            foreach (var value in values)
            {
                valueI++;

#if EF5 || EF6
                // FIND the mapped column
                var column = mapping.ScalarProperties.Find(x => x.Name == value.Key);
                if (column == null)
                {
                    throw new Exception("The destination column could not be found:" + value.Key);
                }
                var columnName = column.ColumnName;
#elif EFCORE
                var property        = entity.FindProperty(value.Key);
                var mappingProperty = dynamicProviderProperty.Invoke(null, new[] { property });

                var columnNameProperty = mappingProperty.GetType().GetProperty("ColumnName", BindingFlags.Public | BindingFlags.Instance);
                var columnName         = (string)columnNameProperty.GetValue(mappingProperty);
#endif

                if (value.Value is Expression)
                {
                    // Oops! the value is not resolved yet!
                    ParameterExpression parameterExpression = null;
                    ((Expression)value.Value).Visit((ParameterExpression p) =>
                    {
                        if (p.Type == typeof(T))
                        {
                            parameterExpression = p;
                        }

                        return(p);
                    });

                    // GET the update value by creating a new select command
                    Type[] typeArguments    = { typeof(T), ((Expression)value.Value).Type };
                    var    lambdaExpression = Expression.Lambda(((Expression)value.Value), parameterExpression);
                    var    selectExpression = Expression.Call(
                        typeof(Queryable),
                        "Select",
                        typeArguments,
                        Expression.Constant(query),
                        lambdaExpression);
                    var result = Expression.Lambda(selectExpression).Compile().DynamicInvoke();
#if EF5 || EF6
                    // GET the select command text
                    var commandText = ((IQueryable)result).ToString();
                    var parameters  = ((IQueryable)result).GetObjectQuery().Parameters;

                    // GET the 'value' part
                    var pos = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf("FROM", StringComparison.InvariantCultureIgnoreCase) - 6;

                    var valueSql = commandText.Substring(6, pos);

                    // Add the destination name
                    valueSql = valueSql.Replace("AS [C1]", "");
                    valueSql = valueSql.Replace("AS `C1`", "");

                    var listReplace = new List <string>()
                    {
                        "[Extent1]",
                        "[Extent2]",
                        "[Extent3]",
                        "[Extent4]",
                        "[Extent5]",
                        "[Extent6]",
                        "[Extent7]",
                        "[Extent8]",
                        "[Extent9]",
                        "[Filter1]",
                        "[Filter2]",
                        "[Filter3]",
                        "[Filter4]",
                        "[Filter5]",
                        "[Filter6]",
                        "`Extent1`",
                        "`Extent2`",
                        "`Extent3`",
                        "`Extent4`",
                        "`Extent5`",
                        "`Extent6`",
                        "`Extent7`",
                        "`Extent8`",
                        "`Extent9`",
                        "`Filter1`",
                        "`Filter2`",
                        "`Filter3`",
                        "`Filter4`",
                        "`Filter5`",
                        "`Filter6`",
                    };

                    // Replace the first value found only!
                    foreach (var itemReplace in listReplace)
                    {
                        if (valueSql.Contains(itemReplace))
                        {
                            valueSql = valueSql.Replace(itemReplace, "B");
                            break;
                        }
                    }

                    // CHECK if valueSql end with ' AS [XYZ]'
                    if (valueSql.LastIndexOf('[') != -1 && valueSql.Substring(0, valueSql.LastIndexOf('[')).EndsWith(" AS ", StringComparison.InvariantCulture))
                    {
                        valueSql = valueSql.Substring(0, valueSql.LastIndexOf('[') - 4);
                    }

                    if (valueSql.LastIndexOf('`') != -1 && valueSql.Substring(0, valueSql.LastIndexOf('`')).EndsWith(" AS ", StringComparison.InvariantCulture))
                    {
                        valueSql = valueSql.Substring(0, valueSql.LastIndexOf('`') - 4);
                    }
#elif EFCORE
                    RelationalQueryContext queryContext;
                    var command     = ((IQueryable)result).CreateCommand(out queryContext);
                    var commandText = command.CommandText;

#if NETSTANDARD1_3
                    // GET the 'value' part
                    var pos = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) != -1 ?
                              commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.CurrentCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.CurrentCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.CurrentCultureIgnoreCase) - 6 :
                              commandText.IndexOf("FROM", StringComparison.CurrentCultureIgnoreCase) - 6;

                    var valueSql = commandText.Substring(6, pos);
#else
                    // GET the 'value' part
                    var pos = commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf("AS [value]" + Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "    FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) != -1 ?
                              commandText.IndexOf(Environment.NewLine + "FROM", StringComparison.InvariantCultureIgnoreCase) - 6 :
                              commandText.IndexOf("FROM", StringComparison.InvariantCultureIgnoreCase) - 6;

                    var valueSql = commandText.Substring(6, pos);
#endif

                    valueSql = valueSql.Trim();

                    // Add the destination name
                    valueSql = valueSql.Replace("[x]", "B");
                    valueSql = valueSql.Replace("[c]", "B");

                    if (valueSql.Length > 0 &&
                        valueSql[0] == '[' &&
                        valueSql.IndexOf("]", StringComparison.CurrentCultureIgnoreCase) != -1 &&
                        valueSql.IndexOf("]", StringComparison.CurrentCultureIgnoreCase) == valueSql.IndexOf("].[", StringComparison.CurrentCultureIgnoreCase)
                        )
                    {
                        // Could contains [something].[column]

                        // GET the tag
                        var tagToReplace = valueSql.Substring(0, valueSql.IndexOf("]", StringComparison.CurrentCultureIgnoreCase) + 1);
                        valueSql = valueSql.Replace(tagToReplace, "B");
                    }
#endif
#if EF5 || EF6
                    foreach (var additionalParameter in parameters)
                    {
                        var newName      = additionalParameter.Name + "_" + valueI;
                        var newParameter = new ObjectParameter(newName, additionalParameter.Value);
                        destinationValues.Add(new Tuple <string, object>(columnName, newParameter));

                        valueSql = valueSql.Replace(additionalParameter.Name, newName);
                    }

                    // TODO: For EF Core?
#endif

                    destinationValues.Add(new Tuple <string, object>(columnName, Expression.Constant(valueSql)));
                }
                else
                {
                    destinationValues.Add(new Tuple <string, object>(columnName, value.Value ?? DBNull.Value));
                }
            }

            return(destinationValues);
        }
예제 #20
0
 private static IPropertyBase TryGetPropertyBase(IEntityType entityType, string propertyName)
 => (IPropertyBase)entityType.FindProperty(propertyName)
 ?? entityType.FindNavigation(propertyName);
 private static IPropertyBase TryGetPropertyBase(IEntityType entityType, string propertyName)
     => (IPropertyBase)entityType.FindProperty(propertyName)
        ?? entityType.FindNavigation(propertyName);
예제 #22
0
        /// <summary>
        /// Extract property metadata from the match expression
        /// </summary>
        /// <typeparam name="TEntity">Type of the entity being upserted</typeparam>
        /// <param name="entityType">Metadata type of the entity being upserted</param>
        /// <param name="matchExpression">The match expression provided by the user</param>
        /// <returns>A list of model properties used to match entities</returns>
        protected List <IProperty> ProcessMatchExpression <TEntity>(IEntityType entityType, Expression <Func <TEntity, object> > matchExpression)
        {
            List <IProperty> joinColumns;

            if (matchExpression is null)
            {
                joinColumns = entityType.GetProperties()
                              .Where(p => p.IsKey())
                              .ToList();
            }
            else if (matchExpression.Body is NewExpression newExpression)
            {
                joinColumns = new List <IProperty>();
                foreach (MemberExpression arg in newExpression.Arguments)
                {
                    if (arg == null || !(arg.Member is PropertyInfo) || !typeof(TEntity).Equals(arg.Expression.Type))
                    {
                        throw new InvalidOperationException("Match columns have to be properties of the TEntity class");
                    }
                    var property = entityType.FindProperty(arg.Member.Name);
                    if (property == null)
                    {
                        throw new InvalidOperationException("Unknown property " + arg.Member.Name);
                    }
                    joinColumns.Add(property);
                }
            }
            else if (matchExpression.Body is UnaryExpression unaryExpression)
            {
                if (!(unaryExpression.Operand is MemberExpression memberExp) || !(memberExp.Member is PropertyInfo) || !typeof(TEntity).Equals(memberExp.Expression.Type))
                {
                    throw new InvalidOperationException("Match columns have to be properties of the TEntity class");
                }
                var property = entityType.FindProperty(memberExp.Member.Name);
                joinColumns = new List <IProperty> {
                    property
                };
            }
            else if (matchExpression.Body is MemberExpression memberExpression)
            {
                if (!typeof(TEntity).Equals(memberExpression.Expression.Type) || !(memberExpression.Member is PropertyInfo))
                {
                    throw new InvalidOperationException("Match columns have to be properties of the TEntity class");
                }
                var property = entityType.FindProperty(memberExpression.Member.Name);
                joinColumns = new List <IProperty> {
                    property
                };
            }
            else
            {
                throw new ArgumentException("match must be an anonymous object initialiser", nameof(matchExpression));
            }

            if (joinColumns.All(p => p.ValueGenerated != ValueGenerated.Never))
            {
                throw new InvalidMatchColumnsException();
            }

            return(joinColumns);
        }
예제 #23
0
        /// <summary>
        /// Extract property metadata from the match expression
        /// </summary>
        /// <typeparam name="TEntity">Type of the entity being upserted</typeparam>
        /// <param name="entityType">Metadata type of the entity being upserted</param>
        /// <param name="matchExpression">The match expression provided by the user</param>
        /// <param name="queryOptions">Options for the current query that will affect it's behaviour</param>
        /// <returns>A list of model properties used to match entities</returns>
        protected static ICollection <IProperty> ProcessMatchExpression <TEntity>(IEntityType entityType, Expression <Func <TEntity, object> >?matchExpression, RunnerQueryOptions queryOptions)
        {
            if (entityType == null)
            {
                throw new ArgumentNullException(nameof(entityType));
            }

            List <IProperty> joinColumns;

            if (matchExpression is null)
            {
                joinColumns = entityType.GetProperties()
                              .Where(p => p.IsKey())
                              .ToList();
            }
            else if (matchExpression.Body is NewExpression newExpression)
            {
                joinColumns = new List <IProperty>();
                foreach (MemberExpression arg in newExpression.Arguments)
                {
                    if (arg == null || arg.Member is not PropertyInfo || !typeof(TEntity).Equals(arg.Expression?.Type))
                    {
                        throw new InvalidOperationException(Resources.MatchColumnsHaveToBePropertiesOfTheTEntityClass);
                    }
                    var property = entityType.FindProperty(arg.Member.Name);
                    if (property == null)
                    {
                        throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Resources.UnknownProperty, arg.Member.Name));
                    }
                    joinColumns.Add(property);
                }
            }
            else if (matchExpression.Body is UnaryExpression unaryExpression)
            {
                if (unaryExpression.Operand is not MemberExpression memberExp || memberExp.Member is not PropertyInfo || !typeof(TEntity).Equals(memberExp.Expression?.Type))
                {
                    throw new InvalidOperationException(Resources.MatchColumnsHaveToBePropertiesOfTheTEntityClass);
                }
                var property = entityType.FindProperty(memberExp.Member.Name);
                if (property == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Resources.UnknownProperty, memberExp.Member.Name));
                }
                joinColumns = new List <IProperty> {
                    property
                };
            }
            else if (matchExpression.Body is MemberExpression memberExpression)
            {
                if (!typeof(TEntity).Equals(memberExpression.Expression?.Type) || memberExpression.Member is not PropertyInfo)
                {
                    throw new InvalidOperationException(Resources.MatchColumnsHaveToBePropertiesOfTheTEntityClass);
                }
                var property = entityType.FindProperty(memberExpression.Member.Name);
                if (property == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Resources.UnknownProperty, memberExpression.Member.Name));
                }
                joinColumns = new List <IProperty> {
                    property
                };
            }
            else
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustBeAnAnonymousObjectInitialiser, "match"), nameof(matchExpression));
            }

            if (!queryOptions.AllowIdentityMatch && joinColumns.Any(p => p.ValueGenerated != ValueGenerated.Never))
            {
                throw new InvalidMatchColumnsException();
            }

            return(joinColumns);
        }
예제 #24
0
        /// <summary>
        ///     Generates code for the annotations on an entity type.
        /// </summary>
        /// <param name="builderName"> The name of the builder variable. </param>
        /// <param name="entityType"> The entity type. </param>
        /// <param name="stringBuilder"> The builder code is added to. </param>
        protected virtual void GenerateEntityTypeAnnotations(
            [NotNull] string builderName,
            [NotNull] IEntityType entityType,
            [NotNull] IndentedStringBuilder stringBuilder)
        {
            Check.NotNull(builderName, nameof(builderName));
            Check.NotNull(entityType, nameof(entityType));
            Check.NotNull(stringBuilder, nameof(stringBuilder));

            var annotations         = entityType.GetAnnotations().ToList();
            var tableNameAnnotation = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.TableName);
            var schemaAnnotation    = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.Schema);

            stringBuilder
            .AppendLine()
            .AppendLine()
            .Append(builderName)
            .Append(".")
            .Append(nameof(RelationalEntityTypeBuilderExtensions.ToTable))
            .Append("(")
            .Append(Code.Literal((string)tableNameAnnotation?.Value ?? entityType.DisplayName()));
            annotations.Remove(tableNameAnnotation);

            if (schemaAnnotation?.Value != null)
            {
                stringBuilder
                .Append(",")
                .Append(Code.Literal((string)schemaAnnotation.Value));
                annotations.Remove(schemaAnnotation);
            }

            stringBuilder.AppendLine(");");

            var discriminatorPropertyAnnotation = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.DiscriminatorProperty);
            var discriminatorValueAnnotation    = annotations.FirstOrDefault(a => a.Name == RelationalAnnotationNames.DiscriminatorValue);

            if ((discriminatorPropertyAnnotation ?? discriminatorValueAnnotation) != null)
            {
                stringBuilder
                .AppendLine()
                .Append(builderName)
                .Append(".")
                .Append(nameof(RelationalEntityTypeBuilderExtensions.HasDiscriminator));

                if (discriminatorPropertyAnnotation?.Value != null)
                {
                    var propertyClrType = entityType.FindProperty((string)discriminatorPropertyAnnotation.Value)?.ClrType;
                    stringBuilder
                    .Append("<")
                    .Append(Code.Reference(propertyClrType.UnwrapEnumType()))
                    .Append(">(")
                    .Append(Code.UnknownLiteral(discriminatorPropertyAnnotation.Value))
                    .Append(")");
                }
                else
                {
                    stringBuilder
                    .Append("()");
                }

                if (discriminatorValueAnnotation?.Value != null)
                {
                    stringBuilder
                    .Append(".")
                    .Append(nameof(DiscriminatorBuilder.HasValue))
                    .Append("(")
                    .Append(Code.UnknownLiteral(discriminatorValueAnnotation.Value))
                    .Append(")");
                }

                stringBuilder.AppendLine(";");

                annotations.Remove(discriminatorPropertyAnnotation);
                annotations.Remove(discriminatorValueAnnotation);
            }

            IgnoreAnnotations(
                annotations,
                RelationshipDiscoveryConvention.NavigationCandidatesAnnotationName,
                RelationshipDiscoveryConvention.AmbiguousNavigationsAnnotationName,
                InversePropertyAttributeConvention.InverseNavigationsAnnotationName,
                CoreAnnotationNames.ConstructorBinding);

            if (annotations.Any())
            {
                foreach (var annotation in annotations)
                {
                    stringBuilder
                    .AppendLine()
                    .Append(builderName);

                    GenerateAnnotation(annotation, stringBuilder);

                    stringBuilder
                    .Append(";")
                    .AppendLine();
                }
            }
        }
예제 #25
0
 public string GetId(IUpdateEntry entry)
 => entry.GetCurrentValue <string>(_entityType.FindProperty(StoreKeyConvention.IdPropertyName));
예제 #26
0
 private static IProperty GetProperty(IEntityType entityType, MemberIdentity memberIdentity)
 => memberIdentity.MemberInfo != null
         ? entityType.FindProperty(memberIdentity.MemberInfo)
         : entityType.FindProperty(memberIdentity.Name);
예제 #27
0
    private static void ValidateTemporalPeriodProperty(IEntityType temporalEntityType, bool periodStart)
    {
        var annotationPropertyName = periodStart
            ? temporalEntityType.GetPeriodStartPropertyName()
            : temporalEntityType.GetPeriodEndPropertyName();

        if (annotationPropertyName == null)
        {
            throw new InvalidOperationException(
                      SqlServerStrings.TemporalMustDefinePeriodProperties(
                          temporalEntityType.DisplayName()));
        }

        var periodProperty = temporalEntityType.FindProperty(annotationPropertyName);

        if (periodProperty == null)
        {
            throw new InvalidOperationException(
                      SqlServerStrings.TemporalExpectedPeriodPropertyNotFound(
                          temporalEntityType.DisplayName(), annotationPropertyName));
        }

        if (!periodProperty.IsShadowProperty() && !temporalEntityType.IsPropertyBag)
        {
            throw new InvalidOperationException(
                      SqlServerStrings.TemporalPeriodPropertyMustBeInShadowState(
                          temporalEntityType.DisplayName(), periodProperty.Name));
        }

        if (periodProperty.IsNullable ||
            periodProperty.ClrType != typeof(DateTime))
        {
            throw new InvalidOperationException(
                      SqlServerStrings.TemporalPeriodPropertyMustBeNonNullableDateTime(
                          temporalEntityType.DisplayName(), periodProperty.Name, nameof(DateTime)));
        }

        const string expectedPeriodColumnName = "datetime2";

        if (periodProperty.GetColumnType() != expectedPeriodColumnName)
        {
            throw new InvalidOperationException(
                      SqlServerStrings.TemporalPeriodPropertyMustBeMappedToDatetime2(
                          temporalEntityType.DisplayName(), periodProperty.Name, expectedPeriodColumnName));
        }

        if (periodProperty.TryGetDefaultValue(out var _))
        {
            throw new InvalidOperationException(
                      SqlServerStrings.TemporalPeriodPropertyCantHaveDefaultValue(
                          temporalEntityType.DisplayName(), periodProperty.Name));
        }

        if (temporalEntityType.GetTableName() is string tableName)
        {
            var storeObjectIdentifier = StoreObjectIdentifier.Table(tableName, temporalEntityType.GetSchema());
            var periodColumnName      = periodProperty.GetColumnName(storeObjectIdentifier);

            var propertiesMappedToPeriodColumn = temporalEntityType.GetProperties().Where(
                p => p.Name != periodProperty.Name && p.GetColumnName(storeObjectIdentifier) == periodColumnName).ToList();
            foreach (var propertyMappedToPeriodColumn in propertiesMappedToPeriodColumn)
            {
                if (propertyMappedToPeriodColumn.ValueGenerated != ValueGenerated.OnAddOrUpdate)
                {
                    throw new InvalidOperationException(
                              SqlServerStrings.TemporalPropertyMappedToPeriodColumnMustBeValueGeneratedOnAddOrUpdate(
                                  temporalEntityType.DisplayName(), propertyMappedToPeriodColumn.Name, nameof(ValueGenerated.OnAddOrUpdate)));
                }

                if (propertyMappedToPeriodColumn.TryGetDefaultValue(out var _))
                {
                    throw new InvalidOperationException(
                              SqlServerStrings.TemporalPropertyMappedToPeriodColumnCantHaveDefaultValue(
                                  temporalEntityType.DisplayName(), propertyMappedToPeriodColumn.Name));
                }
            }
        }

        // TODO: check that period property is excluded from query (once the annotation is added)
    }
예제 #28
0
        private void RunCore <TEntity>(DbContext dbContext, IEntityType entityType, ICollection <TEntity> entities, Expression <Func <TEntity, object> > matchExpression,
                                       Expression <Func <TEntity, TEntity, TEntity> > updateExpression, Expression <Func <TEntity, TEntity, bool> > updateCondition, bool noUpdate) where TEntity : class
        {
            // Find matching entities in the dbContext
            var matches = FindMatches(entityType, entities, dbContext, matchExpression);

            Action <TEntity, TEntity>     updateAction = null;
            Func <TEntity, TEntity, bool> updateTest   = updateCondition?.Compile();

            if (updateExpression != null)
            {
                // If update expression is specified, create an update delegate based on that
                if (!(updateExpression.Body is MemberInitExpression entityUpdater))
                {
                    throw new ArgumentException("updater must be an Initialiser of the TEntity type", nameof(updateExpression));
                }

                var properties = entityUpdater.Bindings.Select(b => b.Member).OfType <PropertyInfo>();
                var updateFunc = updateExpression.Compile();
                updateAction = (dbEntity, newEntity) =>
                {
                    var tmp = updateFunc(dbEntity, newEntity);
                    foreach (var prop in properties)
                    {
                        var property = entityType.FindProperty(prop.Name);
                        prop.SetValue(dbEntity, prop.GetValue(tmp) ?? property.GetDefaultValue());
                    }
                };
            }
            else if (!noUpdate)
            {
                // Otherwise create a default update delegate that updates all non match, non auto generated columns
                var joinColumns = ProcessMatchExpression(entityType, matchExpression);

                var properties = entityType.GetProperties()
                                 .Where(p => p.ValueGenerated == ValueGenerated.Never)
                                 .Select(p => typeof(TEntity).GetProperty(p.Name))
                                 .Where(p => p != null)
                                 .Except(joinColumns.Select(c => c.PropertyInfo));
                updateAction = (dbEntity, newEntity) =>
                {
                    foreach (var prop in properties)
                    {
                        var property = entityType.FindProperty(prop.Name);
                        prop.SetValue(dbEntity, prop.GetValue(newEntity) ?? property.GetDefaultValue());
                    }
                };
            }

            foreach (var(dbEntity, newEntity) in matches)
            {
                if (dbEntity == null)
                {
                    foreach (var prop in typeof(TEntity).GetProperties())
                    {
                        if (prop.GetValue(newEntity) == null)
                        {
                            var property = entityType.FindProperty(prop.Name);
                            if (property != null)
                            {
                                var defaultValue = property.GetDefaultValue();
                                if (defaultValue != null)
                                {
                                    prop.SetValue(newEntity, defaultValue);
                                }
                            }
                        }
                    }
                    dbContext.Add(newEntity);
                    continue;
                }

                if (updateTest?.Invoke(dbEntity, newEntity) == false)
                {
                    continue;
                }

                updateAction?.Invoke(dbEntity, newEntity);
            }
        }
        private static Dictionary <IProperty, object> GetValues(this Driver driver, IEntityType entityType)
        {
            var result = new Dictionary <IProperty, object>();

            result.Add(entityType.FindProperty("CarNumber"), driver.CarNumber);
            result.Add(entityType.FindProperty("Championships"), driver.Championships);
            result.Add(entityType.FindProperty("Id"), driver.Id);
            result.Add(entityType.FindProperty("FastestLaps"), driver.FastestLaps);
            result.Add(entityType.FindProperty("Name"), driver.Name);
            result.Add(entityType.FindProperty("Podiums"), driver.Podiums);
            result.Add(entityType.FindProperty("Poles"), driver.Poles);
            result.Add(entityType.FindProperty("Races"), driver.Races);
            result.Add(entityType.FindProperty("TeamId"), driver.TeamId);
            result.Add(entityType.FindProperty("Version"), driver.Version);
            result.Add(entityType.FindProperty("Wins"), driver.Wins);
            return(result);
        }