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); } } } } } } }
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); }
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); }
private object GetPropValue(string name, object instance) { return(FastProperty.GetProperty(instance.GetType(), name, PropertyCachingStrategy.Cached).GetValue(instance)); }
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); }
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); }