示例#1
0
        private void LoadData <T>(HookingDbContext context, Type type, IList <T> entities, bool loadOnlyPKColumn)
        {
            LoadOnlyPKColumn = loadOnlyPKColumn;
            var entityType = context.Model.FindEntityType(type);

            if (entityType == null)
            {
                type            = entities[0].GetType();
                entityType      = context.Model.FindEntityType(type);
                HasAbstractList = true;
            }
            if (entityType == null)
            {
                throw new InvalidOperationException($"DbContext does not contain EntitySet for Type: { type.Name }");
            }

            //var relationalData = entityType.Relational(); relationalData.Schema relationalData.TableName // DEPRECATED in Core3.0
            var    storeObjectIdent = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table).Value;
            bool   isSqlServer      = context.DataProvider.ProviderType == DbSystemType.SqlServer;
            string defaultSchema    = isSqlServer ? "dbo" : null;

            Schema    = entityType.GetSchema() ?? defaultSchema;
            TableName = entityType.GetTableName();

            TempTableSufix = "Temp";

            if (!BulkConfig.UseTempDB || BulkConfig.UniqueTableNameTempDb)
            {
                TempTableSufix += Guid.NewGuid().ToString().Substring(0, 8); // 8 chars of Guid as tableNameSufix to avoid same name collision with other tables
            }

            bool areSpecifiedUpdateByProperties = BulkConfig.UpdateByProperties?.Count > 0;
            var  primaryKeys = entityType.FindPrimaryKey()?.Properties?.Select(a => a.Name)?.ToList();

            HasSinglePrimaryKey = primaryKeys?.Count == 1;
            PrimaryKeys         = areSpecifiedUpdateByProperties ? BulkConfig.UpdateByProperties : primaryKeys;

            var allProperties = entityType.GetProperties().AsEnumerable();

            // load all derived type properties
            if (entityType.IsAbstract())
            {
                var extendedAllProperties = allProperties.ToList();
                foreach (var derived in entityType.GetDirectlyDerivedTypes())
                {
                    extendedAllProperties.AddRange(derived.GetProperties());
                }

                allProperties = extendedAllProperties.Distinct();
            }

            var ownedTypes = entityType.GetNavigations().Where(a => a.TargetEntityType.IsOwned());

            HasOwnedTypes  = ownedTypes.Any();
            OwnedTypesDict = ownedTypes.ToDictionary(a => a.Name, a => a);

            IdentityColumnName = allProperties.SingleOrDefault(a => a.IsPrimaryKey() && a.ClrType.Name.StartsWith("Int") && a.ValueGenerated == ValueGenerated.OnAdd)?.GetColumnName(storeObjectIdent); // ValueGenerated equals OnAdd even for nonIdentity column like Guid so we only type int as second condition

            // timestamp/row version properties are only set by the Db, the property has a [Timestamp] Attribute or is configured in FluentAPI with .IsRowVersion()
            // They can be identified by the columne type "timestamp" or .IsConcurrencyToken in combination with .ValueGenerated == ValueGenerated.OnAddOrUpdate
            string timestampDbTypeName = nameof(TimestampAttribute).Replace("Attribute", "").ToLower(); // = "timestamp";
            var    timeStampProperties = allProperties.Where(a => (a.IsConcurrencyToken && a.ValueGenerated == ValueGenerated.OnAddOrUpdate) || a.GetColumnType() == timestampDbTypeName);

            TimeStampColumnName = timeStampProperties.FirstOrDefault()?.GetColumnName(storeObjectIdent); // can be only One
            var allPropertiesExceptTimeStamp = allProperties.Except(timeStampProperties);
            var properties = allPropertiesExceptTimeStamp.Where(a => a.GetComputedColumnSql() == null);

            // TimeStamp prop. is last column in OutputTable since it is added later with varbinary(8) type in which Output can be inserted
            OutputPropertyColumnNamesDict   = allPropertiesExceptTimeStamp.Concat(timeStampProperties).ToDictionary(a => a.Name, b => b.GetColumnName(storeObjectIdent).Replace("]", "]]")); // square brackets have to be escaped
            ColumnNameContainsSquareBracket = allPropertiesExceptTimeStamp.Concat(timeStampProperties).Any(a => a.GetColumnName(storeObjectIdent).Contains("]"));

            bool AreSpecifiedPropertiesToInclude = BulkConfig.PropertiesToInclude?.Count() > 0;
            bool AreSpecifiedPropertiesToExclude = BulkConfig.PropertiesToExclude?.Count() > 0;

            if (AreSpecifiedPropertiesToInclude)
            {
                if (areSpecifiedUpdateByProperties) // Adds UpdateByProperties to PropertyToInclude if they are not already explicitly listed
                {
                    foreach (var updateByProperty in BulkConfig.UpdateByProperties)
                    {
                        if (!BulkConfig.PropertiesToInclude.Contains(updateByProperty))
                        {
                            BulkConfig.PropertiesToInclude.Add(updateByProperty);
                        }
                    }
                }
                else // Adds PrimaryKeys to PropertyToInclude if they are not already explicitly listed
                {
                    foreach (var primaryKey in PrimaryKeys)
                    {
                        if (!BulkConfig.PropertiesToInclude.Contains(primaryKey))
                        {
                            BulkConfig.PropertiesToInclude.Add(primaryKey);
                        }
                    }
                }
            }

            foreach (var property in allProperties)
            {
                if (property.PropertyInfo != null) // skip Shadow Property
                {
                    FastPropertyDict.Add(property.Name, FastProperty.GetProperty(property.PropertyInfo));
                }
            }

            UpdateByPropertiesAreNullable = properties.Any(a => PrimaryKeys != null && PrimaryKeys.Contains(a.Name) && a.IsNullable);

            if (AreSpecifiedPropertiesToInclude || AreSpecifiedPropertiesToExclude)
            {
                if (AreSpecifiedPropertiesToInclude && AreSpecifiedPropertiesToExclude)
                {
                    throw new InvalidOperationException("Only one group of properties, either PropertiesToInclude or PropertiesToExclude can be specified, specifying both not allowed.");
                }
                if (AreSpecifiedPropertiesToInclude)
                {
                    properties = properties.Where(a => BulkConfig.PropertiesToInclude.Contains(a.Name));
                }
                if (AreSpecifiedPropertiesToExclude)
                {
                    properties = properties.Where(a => !BulkConfig.PropertiesToExclude.Contains(a.Name));
                }
            }

            if (loadOnlyPKColumn)
            {
                PropertyColumnNamesDict = properties.Where(a => PrimaryKeys.Contains(a.Name)).ToDictionary(a => a.Name, b => b.GetColumnName(storeObjectIdent).Replace("]", "]]"));
            }
            else
            {
                PropertyColumnNamesDict = properties.ToDictionary(a => a.Name, b => b.GetColumnName(storeObjectIdent).Replace("]", "]]"));
                ShadowProperties        = new HashSet <string>(properties.Where(p => p.IsShadowProperty() && !p.IsForeignKey()).Select(p => p.GetColumnName(storeObjectIdent)));
                foreach (var property in properties.Where(p => p.GetValueConverter() != null))
                {
                    string         columnName = property.GetColumnName(storeObjectIdent);
                    ValueConverter converter  = property.GetValueConverter();
                    ConvertibleProperties.Add(columnName, converter);
                }

                foreach (var navigation in entityType.GetNavigations().Where(x => !x.IsCollection && !x.TargetEntityType.IsOwned()))
                {
                    FastPropertyDict.Add(navigation.Name, FastProperty.GetProperty(navigation.PropertyInfo));
                }

                if (HasOwnedTypes)  // Support owned entity property update. TODO: Optimize
                {
                    foreach (var navgationProperty in ownedTypes)
                    {
                        var property = navgationProperty.PropertyInfo;
                        FastPropertyDict.Add(property.Name, FastProperty.GetProperty(property));

                        Type navOwnedType    = type.Assembly.GetType(property.PropertyType.FullName);
                        var  ownedEntityType = context.Model.FindEntityType(property.PropertyType);
                        if (ownedEntityType == null) // when entity has more then one ownedType (e.g. Address HomeAddress, Address WorkAddress) or one ownedType is in multiple Entities like Audit is usually.
                        {
                            ownedEntityType = context.Model.GetEntityTypes().SingleOrDefault(a => a.DefiningNavigationName == property.Name && a.DefiningEntityType.Name == entityType.Name);
                        }
                        var ownedEntityProperties = ownedEntityType.GetProperties().ToList();
                        var ownedEntityPropertyNameColumnNameDict = new Dictionary <string, string>();
                        var ownedStoreObjectIdent = StoreObjectIdentifier.Create(ownedEntityType, StoreObjectType.Table).Value;

                        foreach (var ownedEntityProperty in ownedEntityProperties)
                        {
                            if (!ownedEntityProperty.IsPrimaryKey())
                            {
                                string columnName = ownedEntityProperty.GetColumnName(ownedStoreObjectIdent);
                                ownedEntityPropertyNameColumnNameDict.Add(ownedEntityProperty.Name, columnName);
                                var ownedEntityPropertyFullName = property.Name + "_" + ownedEntityProperty.Name;
                                if (!FastPropertyDict.ContainsKey(ownedEntityPropertyFullName))
                                {
                                    FastPropertyDict.Add(ownedEntityPropertyFullName, FastProperty.GetProperty(ownedEntityProperty.PropertyInfo));
                                }
                            }

                            var converter = ownedEntityProperty.GetValueConverter();
                            if (converter != null)
                            {
                                ConvertibleProperties.Add($"{navgationProperty.Name}_{ownedEntityProperty.Name}", converter);
                            }
                        }
                        var ownedProperties = property.PropertyType.GetProperties();
                        foreach (var ownedProperty in ownedProperties)
                        {
                            if (ownedEntityPropertyNameColumnNameDict.ContainsKey(ownedProperty.Name))
                            {
                                string columnName        = ownedEntityPropertyNameColumnNameDict[ownedProperty.Name];
                                var    ownedPropertyType = Nullable.GetUnderlyingType(ownedProperty.PropertyType) ?? ownedProperty.PropertyType;

                                bool doAddProperty = true;
                                if (AreSpecifiedPropertiesToInclude && !BulkConfig.PropertiesToInclude.Contains(columnName))
                                {
                                    doAddProperty = false;
                                }
                                if (AreSpecifiedPropertiesToExclude && BulkConfig.PropertiesToExclude.Contains(columnName))
                                {
                                    doAddProperty = false;
                                }

                                if (doAddProperty)
                                {
                                    PropertyColumnNamesDict.Add(property.Name + "." + ownedProperty.Name, columnName);
                                    OutputPropertyColumnNamesDict.Add(property.Name + "." + ownedProperty.Name, columnName);
                                }
                            }
                        }
                    }
                }
            }
        }
示例#2
0
        public bool SetProperty <TProp>(
            ImportResult result,
            string columnName,
            Expression <Func <T, TProp> > prop,
            TProp defaultValue = default(TProp),
            Func <object, CultureInfo, TProp> converter = null)
        {
            // TBD: (MC) do not check or validate for perf reason?
            //CheckInitialized();

            var isPropertySet = false;
            var pi            = prop.ExtractPropertyInfo();
            var propName      = pi.Name;
            var target        = _entity;

            columnName = columnName ?? propName;

            try
            {
                object value;
                var    mapping = _segmenter.ColumnMap.GetMapping(columnName);

                if (mapping.IgnoreProperty)
                {
                    // explicitly ignore this property
                }
                else if (_row.TryGetValue(mapping.MappedName, out value) && value != null && value != DBNull.Value && !value.ToString().IsCaseInsensitiveEqual(ExplicitIgnore))
                {
                    // source contains field value. Set it.
                    TProp converted;
                    if (converter != null)
                    {
                        converted = converter(value, _segmenter.Culture);
                    }
                    else if (value.ToString().IsCaseInsensitiveEqual(ExplicitNull))
                    {
                        // prop is "explicitly" set to null. Don't fallback to any default!
                        converted = default(TProp);
                    }
                    else
                    {
                        converted = value.Convert <TProp>(_segmenter.Culture);
                    }

                    var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached);
                    fastProp.SetValue(target, converted);
                    isPropertySet = true;
                }
                else
                {
                    // source field value does not exist or is null/empty
                    if (IsNew)
                    {
                        // if entity is new and source field value is null, determine default value in this particular order:
                        //		2.) Default value in field mapping table
                        //		3.) passed default value argument
                        defaultValue = GetDefaultValue(mapping, defaultValue, result);

                        // source does not contain field data or is empty...
                        if (defaultValue != null)
                        {
                            // ...but the entity is new. In this case set the default value if given.
                            var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached);
                            fastProp.SetValue(target, defaultValue);
                            isPropertySet = true;
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                result.AddWarning("Conversion failed: " + exception.Message, this.GetRowInfo(), propName);
            }

            if (isPropertySet && !_isDirty)
            {
                _isDirty = true;
            }

            return(isPropertySet);
        }
示例#3
0
        private object GetModelFromExpression(string expression, IDictionary <string, object> models, IDictionary <string, Func <object> > factories)
        {
            object currentModel = null;
            int    dotIndex     = 0;
            int    len          = expression.Length;
            bool   bof          = true;
            string token        = null;

            for (var i = 0; i < len; i++)
            {
                if (expression[i] == '.')
                {
                    bof   = false;
                    token = expression.Substring(0, i);
                }
                else if (i == len - 1)
                {
                    // End reached
                    token = expression;
                }
                else
                {
                    continue;
                }

                if (!models.TryGetValue(token, out currentModel))
                {
                    if (bof)
                    {
                        // It's a simple dot-less expression where the token
                        // is actually the model name
                        currentModel = factories.Get(token)?.Invoke();
                    }
                    else
                    {
                        // Sub-token, e.g. "Order.Customer"
                        // Get "Customer" part, this is our property name, NOT the model name
                        var propName = token.Substring(dotIndex + 1);
                        // Get parent model "Order"
                        var parentModel = models.Get(token.Substring(0, dotIndex));
                        if (parentModel == null)
                        {
                            break;
                        }

                        if (parentModel is ITestModel)
                        {
                            // When the parent model is a test model, we need to create a random instance
                            // instead of using the property value (which is null/void in this case)
                            currentModel = factories.Get(propName)?.Invoke();
                        }
                        else
                        {
                            // Get "Customer" property of Order
                            var fastProp = FastProperty.GetProperty(parentModel.GetType(), propName, PropertyCachingStrategy.Uncached);
                            if (fastProp != null)
                            {
                                // Get "Customer" value
                                var propValue = fastProp.GetValue(parentModel);
                                if (propValue != null)
                                {
                                    currentModel = propValue;
                                    //// Resolve logical model name...
                                    //var modelName = _modelProvider.ResolveModelName(propValue);
                                    //if (modelName != null)
                                    //{
                                    //	// ...and create the value
                                    //	currentModel = factories.Get(modelName)?.Invoke();
                                    //}
                                }
                            }
                        }
                    }

                    if (currentModel == null)
                    {
                        break;
                    }

                    // Put it in dict as e.g. "Order.Customer"
                    models[token] = currentModel;
                }

                if (!bof)
                {
                    dotIndex = i;
                }
            }

            return(currentModel);
        }
示例#4
0
 private object GetPropValue(string name, object instance)
 {
     return(FastProperty.GetProperty(instance.GetType(), name, PropertyCachingStrategy.Cached).GetValue(instance));
 }
示例#5
0
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var valueType    = objectType.GetGenericArguments()[0];
            var sequenceType = typeof(List <>).MakeGenericType(objectType);

            object objValue    = null;
            object objChildren = null;
            string id          = null;
            Dictionary <string, object> metadata = null;

            reader.Read();
            while (reader.TokenType == JsonToken.PropertyName)
            {
                string a = reader.Value.ToString();
                if (string.Equals(a, "Value", StringComparison.OrdinalIgnoreCase))
                {
                    reader.Read();
                    objValue = serializer.Deserialize(reader, valueType);
                }
                else if (string.Equals(a, "Metadata", StringComparison.OrdinalIgnoreCase))
                {
                    reader.Read();
                    metadata = serializer.Deserialize <Dictionary <string, object> >(reader);
                }
                else if (string.Equals(a, "Children", StringComparison.OrdinalIgnoreCase))
                {
                    reader.Read();
                    objChildren = serializer.Deserialize(reader, sequenceType);
                }
                if (string.Equals(a, "Id", StringComparison.OrdinalIgnoreCase))
                {
                    reader.Read();
                    id = serializer.Deserialize <string>(reader);
                }
                else
                {
                    reader.Skip();
                }

                reader.Read();
            }

            var ctorParams = objChildren != null
                                ? new object[] { objValue, objChildren }
                                : new object[] { objValue };

            var treeNode = Activator.CreateInstance(objectType, ctorParams);

            // Set Metadata
            if (metadata != null && metadata.Count > 0)
            {
                var metadataProp = FastProperty.GetProperty(objectType, "Metadata", PropertyCachingStrategy.Cached);
                metadataProp.SetValue(treeNode, metadata);

                if (id.HasValue())
                {
                    var idProp = FastProperty.GetProperty(objectType, "Id", PropertyCachingStrategy.Cached);
                    idProp.SetValue(treeNode, id);
                }
            }

            return(treeNode);
        }
示例#6
0
        public bool SetProperty <TProp>(
            ImportResult result,
            T target,
            Expression <Func <T, TProp> > prop,
            TProp defaultValue = default(TProp),
            Func <object, CultureInfo, TProp> converter = null)
        {
            // TBD: (MC) do not check for perf reason?
            //CheckInitialized();

            var isPropertySet = false;
            var pi            = prop.ExtractPropertyInfo();
            var propName      = pi.Name;

            try
            {
                object value;
                var    mapping = _segmenter.ColumnMap.GetMapping(propName);

                if (_row.TryGetValue(mapping.Property, out value))
                {
                    // source contains field value. Set it.
                    TProp converted;
                    if (converter != null)
                    {
                        converted = converter(value, _segmenter.Culture);
                    }
                    else if (value == DBNull.Value || value.ToString().IsCaseInsensitiveEqual("NULL"))
                    {
                        converted = GetDefaultValue(mapping, propName, defaultValue, result);
                    }
                    else
                    {
                        converted = value.Convert <TProp>(_segmenter.Culture);
                    }

                    var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached);
                    fastProp.SetValue(target, converted);
                    isPropertySet = true;
                }
                else
                {
                    if (IsTransient)
                    {
                        defaultValue = GetDefaultValue(mapping, propName, defaultValue, result);

                        // source does not contain field data or is empty...
                        if (defaultValue != null)
                        {
                            // ...but the entity is new. In this case set the default value if given.
                            var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached);
                            fastProp.SetValue(target, defaultValue);
                            isPropertySet = true;
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                result.AddWarning("Conversion failed: " + exception.Message, this.GetRowInfo(), propName);
            }

            return(isPropertySet);
        }