/// <summary> /// Create a new handler instance. /// </summary> public NetTopologySuiteGeographyHandler() { _writer = new SqlServerBytesWriter { IsGeography = true }; _reader = new SqlServerBytesReader { IsGeography = true }; }
protected override byte[] FromGeometry(object value) { var geometry = value as Geometry; if (geometry == null) { return(null); } SetDefaultSRID(geometry); var writer = new SqlServerBytesWriter { IsGeography = IsGeography }; var bytes = writer.Write(geometry); return(bytes); }
/// <summary> /// Common logic for two versions of GetDataTable /// </summary> /// <typeparam name="T"></typeparam> /// <param name="context"></param> /// <param name="type"></param> /// <param name="entities"></param> /// <param name="tableInfo"></param> /// <returns></returns> private static DataTable InnerGetDataTable <T>(DbContext context, ref Type type, IList <T> entities, TableInfo tableInfo) { var dataTable = new DataTable(); var columnsDict = new Dictionary <string, object>(); var ownedEntitiesMappedProperties = new HashSet <string>(); var isSqlServer = context.Database.ProviderName.EndsWith(DbServer.SqlServer.ToString()); var sqlServerBytesWriter = new SqlServerBytesWriter { IsGeography = true }; var objectIdentifier = tableInfo.ObjectIdentifier; type = tableInfo.HasAbstractList ? entities[0].GetType() : type; var entityType = context.Model.FindEntityType(type); var entityTypeProperties = entityType.GetProperties(); var entityPropertiesDict = entityTypeProperties.Where(a => tableInfo.PropertyColumnNamesDict.ContainsKey(a.Name) || (tableInfo.BulkConfig.OperationType != OperationType.Read && a.Name == tableInfo.TimeStampPropertyName)) .ToDictionary(a => a.Name, a => a); var entityNavigationOwnedDict = entityType.GetNavigations().Where(a => a.TargetEntityType.IsOwned()).ToDictionary(a => a.Name, a => a); var entityShadowFkPropertiesDict = entityTypeProperties.Where(a => a.IsShadowProperty() && a.IsForeignKey() && a.GetContainingForeignKeys().FirstOrDefault()?.DependentToPrincipal?.Name != null) .ToDictionary(a => a.Name, a => a); var entityShadowFkPropertyColumnNamesDict = entityShadowFkPropertiesDict.ToDictionary(a => a.Key, a => a.Value.GetColumnName(objectIdentifier)); var shadowPropertyColumnNamesDict = entityPropertiesDict.Where(a => a.Value.IsShadowProperty()).ToDictionary(a => a.Key, a => a.Value.GetColumnName(objectIdentifier)); var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var discriminatorColumn = GetDiscriminatorColumn(tableInfo); foreach (var property in properties) { if (entityPropertiesDict.ContainsKey(property.Name)) { var propertyEntityType = entityPropertiesDict[property.Name]; string columnName = propertyEntityType.GetColumnName(objectIdentifier); var isConvertible = tableInfo.ConvertibleColumnConverterDict.ContainsKey(columnName); var propertyType = isConvertible ? tableInfo.ConvertibleColumnConverterDict[columnName].ProviderClrType : property.PropertyType; var underlyingType = Nullable.GetUnderlyingType(propertyType); if (underlyingType != null) { propertyType = underlyingType; } if (isSqlServer && (propertyType == typeof(Geometry) || propertyType.IsSubclassOf(typeof(Geometry)))) { propertyType = typeof(byte[]); tableInfo.HasSpatialType = true; if (tableInfo.BulkConfig.PropertiesToIncludeOnCompare != null || tableInfo.BulkConfig.PropertiesToIncludeOnCompare != null) { throw new InvalidOperationException("OnCompare properties Config can not be set for Entity with Spatial types like 'Geometry'"); } } if (!columnsDict.ContainsKey(property.Name)) { dataTable.Columns.Add(columnName, propertyType); columnsDict.Add(property.Name, null); } } else if (entityShadowFkPropertiesDict.ContainsKey(property.Name)) { var fk = entityShadowFkPropertiesDict[property.Name]; entityPropertiesDict.TryGetValue(fk.GetColumnName(objectIdentifier), out var entityProperty); if (entityProperty == null) // BulkRead { continue; } var columnName = entityProperty.GetColumnName(objectIdentifier); var propertyType = entityProperty.ClrType; var underlyingType = Nullable.GetUnderlyingType(propertyType); if (underlyingType != null) { propertyType = underlyingType; } if (propertyType == typeof(Geometry) && isSqlServer) { propertyType = typeof(byte[]); } if (!columnsDict.ContainsKey(property.Name)) { dataTable.Columns.Add(columnName, propertyType); columnsDict.Add(columnName, null); } } else if (entityNavigationOwnedDict.ContainsKey(property.Name)) // isOWned { Type navOwnedType = type.Assembly.GetType(property.PropertyType.FullName); var ownedEntityType = context.Model.FindEntityType(property.PropertyType); if (ownedEntityType == null) { 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>(); foreach (var ownedEntityProperty in ownedEntityProperties) { if (!ownedEntityProperty.IsPrimaryKey()) { string columnName = ownedEntityProperty.GetColumnName(objectIdentifier); if (tableInfo.PropertyColumnNamesDict.ContainsValue(columnName)) { ownedEntityPropertyNameColumnNameDict.Add(ownedEntityProperty.Name, columnName); ownedEntitiesMappedProperties.Add(property.Name + "_" + ownedEntityProperty.Name); } } } var innerProperties = property.PropertyType.GetProperties(); if (!tableInfo.LoadOnlyPKColumn) { foreach (var innerProperty in innerProperties) { if (ownedEntityPropertyNameColumnNameDict.ContainsKey(innerProperty.Name)) { var columnName = ownedEntityPropertyNameColumnNameDict[innerProperty.Name]; var propertyName = $"{property.Name}_{innerProperty.Name}"; if (tableInfo.ConvertibleColumnConverterDict.ContainsKey(propertyName)) { var convertor = tableInfo.ConvertibleColumnConverterDict[propertyName]; var underlyingType = Nullable.GetUnderlyingType(convertor.ProviderClrType) ?? convertor.ProviderClrType; dataTable.Columns.Add(columnName, underlyingType); } else { var ownedPropertyType = Nullable.GetUnderlyingType(innerProperty.PropertyType) ?? innerProperty.PropertyType; dataTable.Columns.Add(columnName, ownedPropertyType); } columnsDict.Add(property.Name + "_" + innerProperty.Name, null); } } } } } if (tableInfo.BulkConfig.EnableShadowProperties) { foreach (var shadowProperty in entityPropertiesDict.Values.Where(a => a.IsShadowProperty())) { var columnName = shadowProperty.GetColumnName(objectIdentifier); // If a model has an entity which has a relationship without an explicity defined FK, the data table will already contain the foreign key shadow property if (dataTable.Columns.Contains(columnName)) { continue; } var isConvertible = tableInfo.ConvertibleColumnConverterDict.ContainsKey(columnName); var propertyType = isConvertible ? tableInfo.ConvertibleColumnConverterDict[columnName].ProviderClrType : shadowProperty.ClrType; var underlyingType = Nullable.GetUnderlyingType(propertyType); if (underlyingType != null) { propertyType = underlyingType; } if (isSqlServer && (propertyType == typeof(Geometry) || propertyType.IsSubclassOf(typeof(Geometry)))) { propertyType = typeof(byte[]); } dataTable.Columns.Add(columnName, propertyType); columnsDict.Add(shadowProperty.Name, null); } } if (discriminatorColumn != null) { dataTable.Columns.Add(discriminatorColumn, typeof(string)); columnsDict.Add(discriminatorColumn, type.Name); } bool hasConverterProperties = tableInfo.ConvertiblePropertyColumnDict.Count > 0; foreach (var entity in entities) { foreach (var property in properties) { var propertyValue = tableInfo.FastPropertyDict.ContainsKey(property.Name) ? tableInfo.FastPropertyDict[property.Name].Get(entity) : null; if (tableInfo.BulkConfig.DateTime2PrecisionForceRound && isSqlServer && tableInfo.DateTime2PropertiesPrecisionLessThen7Dict.ContainsKey(property.Name)) { DateTime dateTimePropertyValue = (DateTime)propertyValue; int precision = tableInfo.DateTime2PropertiesPrecisionLessThen7Dict[property.Name]; int digitsToRemove = 7 - precision; int powerOf10 = (int)Math.Pow(10, digitsToRemove); long subsecondTicks = dateTimePropertyValue.Ticks % 10000000; long ticksToRound = subsecondTicks + (subsecondTicks % 10 == 0 ? 1 : 0); // if ends with 0 add 1 tick to make sure rounding of value .5_zeros is rounded to Upper like SqlServer is doing, not to Even as Math.Round works int roundedTicks = Convert.ToInt32(Math.Round((decimal)ticksToRound / powerOf10, 0)) * powerOf10; dateTimePropertyValue = dateTimePropertyValue.AddTicks(-subsecondTicks).AddTicks(roundedTicks); propertyValue = dateTimePropertyValue; } if (hasConverterProperties && tableInfo.ConvertiblePropertyColumnDict.ContainsKey(property.Name)) { string columnName = tableInfo.ConvertiblePropertyColumnDict[property.Name]; propertyValue = tableInfo.ConvertibleColumnConverterDict[columnName].ConvertToProvider.Invoke(propertyValue); } if (tableInfo.HasSpatialType && propertyValue is Geometry geometryValue) { geometryValue.SRID = tableInfo.BulkConfig.SRID; propertyValue = sqlServerBytesWriter.Write(geometryValue); } if (entityPropertiesDict.ContainsKey(property.Name)) { columnsDict[property.Name] = propertyValue; } else if (entityShadowFkPropertiesDict.ContainsKey(property.Name)) { var foreignKeyShadowProperty = entityShadowFkPropertiesDict[property.Name]; var columnName = entityShadowFkPropertyColumnNamesDict[property.Name]; entityPropertiesDict.TryGetValue(columnName, out var entityProperty); if (entityProperty == null) // BulkRead { continue; } columnsDict[columnName] = propertyValue == null ? null : foreignKeyShadowProperty.FindFirstPrincipal().PropertyInfo.GetValue(propertyValue); // TODO Check if can be optimized } else if (entityNavigationOwnedDict.ContainsKey(property.Name) && !tableInfo.LoadOnlyPKColumn) { var ownedProperties = property.PropertyType.GetProperties().Where(a => ownedEntitiesMappedProperties.Contains(property.Name + "_" + a.Name)); foreach (var ownedProperty in ownedProperties) { var columnName = $"{property.Name}_{ownedProperty.Name}"; var ownedPropertyValue = propertyValue == null ? null : tableInfo.FastPropertyDict[columnName].Get(propertyValue); if (tableInfo.ConvertibleColumnConverterDict.ContainsKey(columnName)) { var converter = tableInfo.ConvertibleColumnConverterDict[columnName]; columnsDict[columnName] = ownedPropertyValue == null ? null : converter.ConvertToProvider.Invoke(ownedPropertyValue); } else { columnsDict[columnName] = ownedPropertyValue; } } } } if (tableInfo.BulkConfig.EnableShadowProperties) { foreach (var shadowPropertyName in shadowPropertyColumnNamesDict.Keys) { var shadowProperty = entityPropertiesDict[shadowPropertyName]; var columnName = shadowPropertyColumnNamesDict[shadowPropertyName]; var propertyValue = context.Entry(entity).Property(shadowPropertyName).CurrentValue; if (tableInfo.ConvertibleColumnConverterDict.ContainsKey(columnName)) { propertyValue = tableInfo.ConvertibleColumnConverterDict[columnName].ConvertToProvider.Invoke(propertyValue); } columnsDict[shadowPropertyName] = propertyValue; } } var record = columnsDict.Values.ToArray(); dataTable.Rows.Add(record); } return(dataTable); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public GeometryValueConverter(SqlServerBytesReader reader, SqlServerBytesWriter writer) : base( g => new SqlBytes(writer.Write(g)), b => (TGeometry)reader.Read(b.Value)) { }
/// <summary> /// Common logic for two versions of GetDataTable /// </summary> /// <typeparam name="T"></typeparam> /// <param name="context"></param> /// <param name="type"></param> /// <param name="entities"></param> /// <param name="tableInfo"></param> /// <returns></returns> private static DataTable InnerGetDataTable <T>(DbContext context, ref Type type, IList <T> entities, TableInfo tableInfo) { var dataTable = new DataTable(); var columnsDict = new Dictionary <string, object>(); var ownedEntitiesMappedProperties = new HashSet <string>(); var isSqlServer = context.Database.ProviderName.EndsWith(DbServer.SqlServer.ToString()); var sqlServerBytesWriter = new SqlServerBytesWriter { IsGeography = true }; type = tableInfo.HasAbstractList ? entities[0].GetType() : type; var entityType = context.Model.FindEntityType(type); var entityTypeProperties = entityType.GetProperties(); var entityPropertiesDict = entityTypeProperties.Where(a => tableInfo.PropertyColumnNamesDict.ContainsKey(a.Name)).ToDictionary(a => a.Name, a => a); var entityNavigationOwnedDict = entityType.GetNavigations().Where(a => a.GetTargetType().IsOwned()).ToDictionary(a => a.Name, a => a); var entityShadowFkPropertiesDict = entityTypeProperties.Where(a => a.IsShadowProperty() && a.IsForeignKey() && a.GetContainingForeignKeys().FirstOrDefault()?.DependentToPrincipal?.Name != null) .ToDictionary(x => x.Name, a => a); var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var discriminatorColumn = GetDiscriminatorColumn(tableInfo); foreach (var property in properties) { if (entityPropertiesDict.ContainsKey(property.Name)) { var propertyEntityType = entityPropertiesDict[property.Name]; string columnName = propertyEntityType.GetColumnName(); var isConvertible = tableInfo.ConvertibleProperties.ContainsKey(columnName); var propertyType = isConvertible ? tableInfo.ConvertibleProperties[columnName].ProviderClrType : property.PropertyType; var underlyingType = Nullable.GetUnderlyingType(propertyType); if (underlyingType != null) { propertyType = underlyingType; } if (isSqlServer && (propertyType == typeof(Geometry) || propertyType.IsSubclassOf(typeof(Geometry)))) { propertyType = typeof(byte[]); tableInfo.HasSpatialType = true; if (tableInfo.BulkConfig.PropertiesToIncludeOnCompare != null || tableInfo.BulkConfig.PropertiesToIncludeOnCompare != null) { throw new InvalidOperationException("OnCompare properties Config can not be set for Entity with Spatial types like 'Geometry'"); } } if (!columnsDict.ContainsKey(property.Name)) { dataTable.Columns.Add(columnName, propertyType); columnsDict.Add(property.Name, null); } } else if (entityShadowFkPropertiesDict.ContainsKey(property.Name)) { var fk = entityShadowFkPropertiesDict[property.Name]; entityPropertiesDict.TryGetValue(fk.GetColumnName(), out var entityProperty); if (entityProperty == null) // BulkRead { continue; } var columnName = entityProperty.GetColumnName(); var propertyType = entityProperty.ClrType; var underlyingType = Nullable.GetUnderlyingType(propertyType); if (underlyingType != null) { propertyType = underlyingType; } if (propertyType == typeof(Geometry) && isSqlServer) { propertyType = typeof(byte[]); } if (!columnsDict.ContainsKey(property.Name)) { dataTable.Columns.Add(columnName, propertyType); columnsDict.Add(columnName, null); } } else if (entityNavigationOwnedDict.ContainsKey(property.Name)) // isOWned { Type navOwnedType = type.Assembly.GetType(property.PropertyType.FullName); var ownedEntityType = context.Model.FindEntityType(property.PropertyType); if (ownedEntityType == null) { 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>(); foreach (var ownedEntityProperty in ownedEntityProperties) { if (!ownedEntityProperty.IsPrimaryKey()) { string columnName = ownedEntityProperty.GetColumnName(); if (tableInfo.PropertyColumnNamesDict.ContainsValue(columnName)) { ownedEntityPropertyNameColumnNameDict.Add(ownedEntityProperty.Name, columnName); ownedEntitiesMappedProperties.Add(property.Name + "_" + ownedEntityProperty.Name); } } } var innerProperties = property.PropertyType.GetProperties(); if (!tableInfo.LoadOnlyPKColumn) { foreach (var innerProperty in innerProperties) { if (ownedEntityPropertyNameColumnNameDict.ContainsKey(innerProperty.Name)) { var columnName = ownedEntityPropertyNameColumnNameDict[innerProperty.Name]; var propertyName = $"{property.Name}_{innerProperty.Name}"; if (tableInfo.ConvertibleProperties.ContainsKey(propertyName)) { var convertor = tableInfo.ConvertibleProperties[propertyName]; var underlyingType = Nullable.GetUnderlyingType(convertor.ProviderClrType) ?? convertor.ProviderClrType; dataTable.Columns.Add(columnName, underlyingType); } else { var ownedPropertyType = Nullable.GetUnderlyingType(innerProperty.PropertyType) ?? innerProperty.PropertyType; dataTable.Columns.Add(columnName, ownedPropertyType); } columnsDict.Add(property.Name + "_" + innerProperty.Name, null); } } } } } if (tableInfo.BulkConfig.EnableShadowProperties) { foreach (var sp in entityPropertiesDict.Values.Where(y => y.IsShadowProperty())) { var columnName = sp.GetColumnName(); // If a model has an entity which has a relationship without an explicity defined FK, the data table will already contain the foreign key shadow property if (dataTable.Columns.Contains(columnName)) { continue; } var isConvertible = tableInfo.ConvertibleProperties.ContainsKey(columnName); var propertyType = isConvertible ? tableInfo.ConvertibleProperties[columnName].ProviderClrType : sp.ClrType; var underlyingType = Nullable.GetUnderlyingType(propertyType); if (underlyingType != null) { propertyType = underlyingType; } if (isSqlServer && (propertyType == typeof(Geometry) || propertyType.IsSubclassOf(typeof(Geometry)))) { propertyType = typeof(byte[]); } dataTable.Columns.Add(columnName, propertyType); columnsDict.Add(sp.Name, null); } } if (discriminatorColumn != null) { dataTable.Columns.Add(discriminatorColumn, typeof(string)); columnsDict.Add(discriminatorColumn, type.Name); } foreach (var entity in entities) { foreach (var property in properties) { var propertyValue = tableInfo.FastPropertyDict.ContainsKey(property.Name) ? tableInfo.FastPropertyDict[property.Name].Get(entity) : null; if (entityPropertiesDict.ContainsKey(property.Name)) { string columnName = entityPropertiesDict[property.Name].GetColumnName(); if (tableInfo.ConvertibleProperties.ContainsKey(columnName)) { propertyValue = tableInfo.ConvertibleProperties[columnName].ConvertToProvider.Invoke(propertyValue); } } if (propertyValue is Geometry geometryValue && isSqlServer) { geometryValue.SRID = tableInfo.BulkConfig.SRID; propertyValue = sqlServerBytesWriter.Write(geometryValue); } if (entityPropertiesDict.ContainsKey(property.Name)) { columnsDict[property.Name] = propertyValue; } else if (entityShadowFkPropertiesDict.ContainsKey(property.Name)) { var fk = entityShadowFkPropertiesDict[property.Name]; var columnName = fk.GetColumnName(); entityPropertiesDict.TryGetValue(fk.GetColumnName(), out var entityProperty); if (entityProperty == null) // BulkRead { continue; } columnsDict[columnName] = propertyValue == null ? null : fk.FindFirstPrincipal().PropertyInfo.GetValue(propertyValue); } else if (entityNavigationOwnedDict.ContainsKey(property.Name) && !tableInfo.LoadOnlyPKColumn) { var ownedProperties = property.PropertyType.GetProperties().Where(a => ownedEntitiesMappedProperties.Contains(property.Name + "_" + a.Name)); foreach (var ownedProperty in ownedProperties) { var columnName = $"{property.Name}_{ownedProperty.Name}"; var ownedPropertyValue = propertyValue == null ? null : tableInfo.FastPropertyDict[columnName].Get(propertyValue); if (tableInfo.ConvertibleProperties.ContainsKey(columnName)) { var converter = tableInfo.ConvertibleProperties[columnName]; columnsDict[columnName] = ownedPropertyValue == null ? null : converter.ConvertToProvider.Invoke(ownedPropertyValue); } else { columnsDict[columnName] = ownedPropertyValue; } } } } if (tableInfo.BulkConfig.EnableShadowProperties) { foreach (var sp in entityPropertiesDict.Values.Where(y => y.IsShadowProperty())) { var propertyValue = context.Entry(entity).Property(sp.Name).CurrentValue; var columnName = sp.GetColumnName(); if (tableInfo.ConvertibleProperties.ContainsKey(columnName)) { propertyValue = tableInfo.ConvertibleProperties[columnName].ConvertToProvider.Invoke(propertyValue); } columnsDict[sp.Name] = propertyValue; } } var record = columnsDict.Values.ToArray(); dataTable.Rows.Add(record); } return(dataTable); }