internal static List <MappingInfo> GetMetadata(DbContext context, Type type) { var metadata = context.Model; var entityType = metadata.GetEntityTypes().Single(x => x.ClrType == type); var tableName = GetTableName(context, type); var columnsInfo = GetColumnsInfo(context, tableName); if (entityType.BaseType != null) { var baseTableName = GetTableName(context, entityType.BaseType.ClrType); if (baseTableName != tableName) { var extraColumnsInfo = GetColumnsInfo(context, baseTableName); columnsInfo.AddRange(extraColumnsInfo); } } var innerList = entityType.GetProperties() .Where(x => x.PropertyInfo != null) .Select(x => { #if !NETSTANDARD2_1 var relational = x.DeclaringEntityType.Relational(); #endif ValueGenerator localGenerator = null; var generatorFactory = x.GetAnnotations().FirstOrDefault(a => a.Name == "ValueGeneratorFactory"); if (generatorFactory != null) { var valueGeneratorAccessor = generatorFactory.Value as Func <IProperty, IEntityType, ValueGenerator>; localGenerator = valueGeneratorAccessor(x, x.DeclaringEntityType); } return(new MappingInfo() { #if NETSTANDARD2_1 TableName = x.DeclaringEntityType.GetTableName(), TableNameQualified = NpgsqlHelper.GetQualifiedName(x.DeclaringEntityType.GetTableName(), x.DeclaringEntityType.GetSchema()), ColumnInfo = columnsInfo.First(c => c.ColumnName == x.GetColumnName()), #else TableName = relational.TableName, TableNameQualified = NpgsqlHelper.GetQualifiedName(relational.TableName, relational.Schema), ColumnInfo = columnsInfo.First(c => c.ColumnName == x.Relational().ColumnName), #endif Property = x.PropertyInfo, IsDbGenerated = x.ValueGenerated != ValueGenerated.Never && localGenerator == null, LocalGenerator = localGenerator, IsKey = x.IsKey(), IsInheritanceUsed = entityType.BaseType != null }); }).ToList(); return(innerList); }
internal object GetSql(EntityInfo mapping) { string conflictAction; if (!doUpdate) { conflictAction = "DO NOTHING"; } else { if (updateProperties == null) { throw new ArgumentNullException(nameof(updateProperties)); } if (updateProperties.Length == 0) { throw new InvalidOperationException("Update properties list update can't be empty"); } if (conflictProperty != null) { if (!mapping.PropToMappingInfo.TryGetValue(UnwrapProperty(conflictProperty), out MappingInfo info)) { throw new InvalidOperationException($"Can't find property {conflictProperty} in mapping"); } conflictTarget = $"({NpgsqlHelper.GetQualifiedName(info.ColumnInfo.ColumnName)})"; } var sb = new StringBuilder(100); sb.Append("DO UPDATE SET "); foreach (var expr in updateProperties) { var updateProp = UnwrapProperty(expr); if (!mapping.PropToMappingInfo.TryGetValue(updateProp, out MappingInfo info)) { throw new InvalidOperationException($"Can't find property {updateProp} in mapping"); } sb.Append(NpgsqlHelper.GetQualifiedName(info.ColumnInfo.ColumnName)); sb.Append(" = EXCLUDED."); sb.Append(NpgsqlHelper.GetQualifiedName(info.ColumnInfo.ColumnName)); sb.Append(", "); } sb.Length -= 2; conflictAction = sb.ToString(); } return($"ON CONFLICT {conflictTarget} {conflictAction}"); }
private List <MappingInfo> GetMappingInfo(Type type, string tableName) { var mappings = NpgsqlHelper.GetMetadata(context, type); mappings.ForEach(x => { var sourceAttribute = x.Property?.GetCustomAttribute <BulkMappingSourceAttribute>(); var modifiers = x.Property?.GetCustomAttributes <BulkOperationModifierAttribute>(); x.ModifierAttributes = modifiers?.ToList() ?? new List <BulkOperationModifierAttribute>(); x.OverrideSourceMethod = GetOverrideSouceFunc(type, sourceAttribute?.PropertyName); x.NpgsqlType = GetNpgsqlType(x.ColumnInfo); x.TempAliasedColumnName = $"{x.TableName}_{x.ColumnInfo.ColumnName}".ToLower(); x.QualifiedColumnName = $"{NpgsqlHelper.GetQualifiedName(x.TableName)}.{NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName)}"; }); return(mappings); }
private List <InsertQueryParts> GetInsertQueryParts( List <MappingInfo> mappingInfo, long optionalFlags) { var grouppedByTables = mappingInfo .GroupBy(x => x.TableName) .Select(x => new { TableName = x.Key, x.First().TableNameQualified, KeyInfos = x.Where(y => y.IsKey).ToList(), ClientDataInfos = x.Where(y => y.DoInsert && (y.IsSpecifiedFlag == 0 || (y.IsSpecifiedFlag & optionalFlags) > 0)).ToList(), ReturningInfos = x.Where(y => y.ReadBack).ToList() }) .ToList(); return(grouppedByTables.Select(x => { var others = grouppedByTables.Where(y => y.TableName != x.TableName) .SelectMany(y => y.ClientDataInfos) .Select(y => new { My = y, Others = x.ReturningInfos.FirstOrDefault(ri => ri.Property.Name == y.Property.Name) }) .Where(y => y.Others != null) .ToList(); return new InsertQueryParts() { TableName = x.TableName, TableNameQualified = x.TableNameQualified, TargetColumnNamesQueryPart = string.Join(", ", x.ClientDataInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName))), SourceColumnNamesQueryPart = string.Join(", ", x.ClientDataInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.TempAliasedColumnName))), Returning = string.Join(", ", x.ReturningInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName))), ReturningSetQueryPart = string.Join(", ", others.Select(y => $"{NpgsqlHelper.GetQualifiedName(y.My.TempAliasedColumnName)} " + $" = source.{NpgsqlHelper.GetQualifiedName(y.Others.ColumnInfo.ColumnName)}")) }; }).ToList()); }
internal List <MappingInfo> ConvertFragmentToMapping( DbContext context, Type type, MappingFragment mappingFragment, EntityType entityType) { var tableEntitySet = mappingFragment.StoreEntitySet; var tableName = (tableEntitySet.MetadataProperties["Table"].Value ?? tableEntitySet.Name).ToString(); var columnsInfo = GetColumnsInfo(context, tableName); var innerList = mappingFragment.PropertyMappings .OfType <ScalarPropertyMapping>() .Select(x => { var columnInfo = columnsInfo.FirstOrDefault(c => c.ColumnName == x.Column.Name); if (columnInfo == null) { throw new InvalidOperationException( $"Column '{x.Column.Name}' (mapped to: '{x.Property.DeclaringType.Name}.{x.Property.Name}') is not found"); } var isDbGenerated = x.Column.IsStoreGeneratedComputed || x.Column.IsStoreGeneratedIdentity; return(new MappingInfo() { TableName = tableName, TableNameQualified = NpgsqlHelper.GetQualifiedName(tableName, tableEntitySet.Schema), Property = type.GetProperty(x.Property.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance), ColumnInfo = columnInfo, IsKey = entityType.KeyProperties.Any(y => y.Name == x.Property.Name), DoUpdate = !isDbGenerated, DoInsert = !isDbGenerated }); }).ToList(); return(innerList); }
internal static List <MappingInfo> GetMetadata(DbContext context, Type type) { var metadata = context.Model; var entityType = metadata.GetEntityTypes().Single(x => x.ClrType == type); var tableName = GetTableName(context, type); var columnsInfo = GetColumnsInfo(context, tableName); if (entityType.BaseType != null) { var baseTableName = GetTableName(context, entityType.BaseType.ClrType); if (baseTableName != tableName) { var extraColumnsInfo = GetColumnsInfo(context, baseTableName); columnsInfo.AddRange(extraColumnsInfo); } } var innerList = entityType.GetProperties() .Where(x => x.PropertyInfo != null) .Select(x => { var relational = x.DeclaringEntityType.Relational(); return(new MappingInfo() { TableName = relational.TableName, TableNameQualified = NpgsqlHelper.GetQualifiedName(relational.TableName, relational.Schema), Property = x.PropertyInfo, ColumnInfo = columnsInfo.First(c => c.ColumnName == x.Relational().ColumnName), IsDbGenerated = x.ValueGenerated != ValueGenerated.Never, IsKey = x.IsKey(), IsInheritanceUsed = entityType.BaseType != null }); }).ToList(); return(innerList); }
private EntityInfo CreateEntityInfo <T>( string tableName, string tableNameQualified, List <MappingInfo> mappingInfo, NpgsqlBulkCodeBuilder <T> codeBuilderOuter = null) { var codeBuilder = codeBuilderOuter ?? new NpgsqlBulkCodeBuilder <T>(); var info = new EntityInfo() { TableNameQualified = tableNameQualified, TableName = tableName, CodeBuilder = codeBuilder, MappingInfos = mappingInfo, PropToMappingInfo = mappingInfo.Where(x => x.Property != null).ToDictionary(x => x.Property.Name), TableNames = mappingInfo.Select(x => x.TableName).Distinct().ToArray(), InsertClientDataInfos = mappingInfo.Where(x => x.DoInsert).ToArray(), UpdateClientDataWithKeysInfos = mappingInfo.Where(x => x.DoUpdate || x.IsKey).ToArray(), MaxIsOptionalFlag = mappingInfo.Max(x => x.IsSpecifiedFlag) }; #if EFCore info.PropertyToGenerators = mappingInfo .Where(x => x.LocalGenerator != null) .ToDictionary(x => x.DbProperty, x => x.LocalGenerator); info.PropertyNameToGenerators = info.PropertyToGenerators.ToDictionary(x => x.Key.Name, x => x.Value); #endif var tableNames = mappingInfo.Select(x => x.TableNameQualified).Distinct().ToList(); //var grouppedByTables = mappingInfo.GroupBy(x => x.TableName) // .Select(x => new // { // TableName = x.Key, // x.First().TableNameQualified, // KeyInfos = x.Where(y => y.IsKey).ToList(), // ClientDataInfos = x.Where(y => y.DoInsert).ToList(), // ReturningInfos = x.Where(y => y.ReadBack).ToList() // }) // .ToList(); info.InsertQueryParts = new ConcurrentDictionary <long, List <InsertQueryParts> >(); info.InsertQueryParts[0] = GetInsertQueryParts(mappingInfo, 0); //info.InsertQueryParts = grouppedByTables.Select(x => //{ // var others = grouppedByTables.Where(y => y.TableName != x.TableName) // .SelectMany(y => y.ClientDataInfos) // .Select(y => new // { // My = y, // Others = x.ReturningInfos.FirstOrDefault(ri => ri.Property.Name == y.Property.Name) // }) // .Where(y => y.Others != null) // .ToList(); // return new InsertQueryParts() // { // TableName = x.TableName, // TableNameQualified = x.TableNameQualified, // TargetColumnNamesQueryPart = string.Join(", ", x.ClientDataInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName))), // SourceColumnNamesQueryPart = string.Join(", ", x.ClientDataInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.TempAliasedColumnName))), // Returning = string.Join(", ", x.ReturningInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName))), // ReturningSetQueryPart = string.Join(", ", others.Select(y => $"{NpgsqlHelper.GetQualifiedName(y.My.TempAliasedColumnName)} " + // $" = source.{NpgsqlHelper.GetQualifiedName(y.Others.ColumnInfo.ColumnName)}")) // }; //}).ToList(); info.SelectSourceForInsertQuery = "SELECT " + string.Join(", ", info.InsertClientDataInfos .Select(x => $"{x.QualifiedColumnName} AS {x.TempAliasedColumnName}")) + " FROM " + string.Join(", ", tableNames); info.CopyColumnsForInsertQueryPart = string.Join(", ", info.InsertClientDataInfos .Select(x => x.TempAliasedColumnName)); info.InsertDbGeneratedInfos = info.MappingInfos.Where(x => x.ReadBack && x.Property != null).ToArray(); // Now time for updates var grouppedByTables = mappingInfo.GroupBy(x => x.TableName) .Select(x => new { TableName = x.Key, x.First().TableNameQualified, KeyInfos = x.Where(y => y.IsKey).ToList(), ClientDataInfos = x.Where(y => y.DoUpdate).ToList(), ReturningInfos = x.Where(y => y.ReadBack).ToList() }) .ToList(); info.UpdateQueryParts = grouppedByTables.Select(x => { var updateableInfos = x.ClientDataInfos; updateableInfos = updateableInfos .Where(y => y.DoUpdate) .Where(y => y.ModifierAttributes == null || y.ModifierAttributes.All(m => m.Modification != BulkOperationModification.IgnoreForUpdate)) .ToList(); return(new UpdateQueryParts() { TableName = x.TableName, TableNameQualified = x.TableNameQualified, SetClause = string.Join(", ", updateableInfos.Select(y => { var colName = NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName); return $"{colName} = source.{y.TempAliasedColumnName}"; })), WhereClause = string.Join(" AND ", x.KeyInfos.Select(y => { var colName = NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName); var clause = $"{colName} = source.{y.TempAliasedColumnName}"; if (y.IsNullableInClr) { clause = $"({clause} OR ({colName} IS NULL AND source.{y.TempAliasedColumnName} IS NULL))"; } return clause; })) }); }) .Where(x => !string.IsNullOrEmpty(x.SetClause)) .ToList(); info.SelectSourceForUpdateQuery = "SELECT " + string.Join(", ", info.UpdateClientDataWithKeysInfos .Select(x => $"{x.QualifiedColumnName} AS {x.TempAliasedColumnName}")) + " FROM " + string.Join(", ", grouppedByTables.Select(x => x.TableNameQualified)); info.CopyColumnsForUpdateQueryPart = string.Join(", ", info.UpdateClientDataWithKeysInfos .Select(x => x.TempAliasedColumnName)); info.UpdateDbGeneratedInfos = info.MappingInfos.Where(x => x.ReadBack && x.Property != null).ToArray(); // Rest info info.KeyInfos = info.MappingInfos.Where(x => x.IsKey).ToArray(); info.KeyColumnNames = info.KeyInfos.Select(x => x.ColumnInfo.ColumnName).ToArray(); if (codeBuilderOuter == null) { codeBuilder.InitBuilder(info, ReadValue); } return(info); }
internal static List <MappingInfo> GetMetadata(DbContext context, Type type) { var metadata = context.Model; var entityType = metadata.GetEntityTypes().Single(x => x.ClrType == type); var tableName = GetTableName(context, type); var columnsInfo = NpgsqlBulkUploader.RelationalHelper.GetColumnsInfo(context, tableName); if (entityType.BaseType != null) { var baseTableName = GetTableName(context, entityType.BaseType.ClrType); if (baseTableName != tableName) { var extraColumnsInfo = NpgsqlBulkUploader.RelationalHelper.GetColumnsInfo(context, baseTableName); columnsInfo.AddRange(extraColumnsInfo); } } int optinalIndex = 0; var innerList = entityType.GetProperties() .Select(x => { var relational = x.DeclaringEntityType; ValueGenerator localGenerator = null; bool isDbGenerated = false; var generatorFactory = x.GetAnnotations().FirstOrDefault(a => a.Name == "ValueGeneratorFactory"); if (generatorFactory != null) { var valueGeneratorAccessor = generatorFactory.Value as Func <IProperty, IEntityType, ValueGenerator>; localGenerator = valueGeneratorAccessor(x, x.DeclaringEntityType); } else if (x.GetAnnotations().Any(y => y.Name == "Relational:ComputedColumnSql")) { isDbGenerated = true; } else if (x.GetAnnotations().Any(y => y.Name == "Npgsql:ValueGenerationStrategy")) { isDbGenerated = true; } var indexes = ((Microsoft.EntityFrameworkCore.Metadata.Internal.Property)x).PropertyIndexes; long optionalFlag = 0; if (indexes.StoreGenerationIndex >= 0 && localGenerator == null) { optionalFlag = 1 << optinalIndex; optinalIndex++; } return(new MappingInfo() { TableName = relational.GetTableName(), TableNameQualified = NpgsqlHelper.GetQualifiedName(relational.GetTableName(), relational.GetSchema()), Property = x.PropertyInfo, ColumnInfo = columnsInfo.First(c => c.ColumnName == x.GetColumnName()), LocalGenerator = localGenerator, ValueConverter = x.GetValueConverter(), IsKey = x.IsKey(), IsInheritanceUsed = entityType.BaseType != null, DbProperty = x, DoUpdate = !isDbGenerated && x.PropertyInfo != null, // don't update shadow props DoInsert = !isDbGenerated, // do insert of shadow props ReadBack = indexes.StoreGenerationIndex >= 0, IsSpecifiedFlag = optionalFlag }); }).ToList(); return(innerList); }
private EntityInfo CreateEntityInfo <T>( string tableName, string tableNameQualified, List <MappingInfo> mappingInfo, NpgsqlBulkCodeBuilder <T> codeBuilderOuter = null) { var codeBuilder = codeBuilderOuter ?? new NpgsqlBulkCodeBuilder <T>(); var info = new EntityInfo() { TableNameQualified = tableNameQualified, TableName = tableName, CodeBuilder = codeBuilder, MappingInfos = mappingInfo, PropToMappingInfo = mappingInfo.ToDictionary(x => x.Property), TableNames = mappingInfo.Select(x => x.TableName).Distinct().ToArray(), ClientDataInfos = mappingInfo.Where(x => !x.IsDbGenerated).ToArray(), ClientDataWithKeysInfos = mappingInfo.Where(x => !x.IsDbGenerated || x.IsKey).ToArray() }; #if NETSTANDARD1_5 || NETSTANDARD2_0 || NETSTANDARD2_1 info.PropertyToGenerators = mappingInfo.Where(x => x.LocalGenerator != null).ToDictionary(x => x.Property, x => x.LocalGenerator); info.PropertyNameToGenerators = info.PropertyToGenerators.ToDictionary(x => x.Key.Name, x => x.Value); #endif var grouppedByTables = mappingInfo.GroupBy(x => x.TableName) .Select(x => new { TableName = x.Key, x.First().TableNameQualified, KeyInfos = x.Where(y => y.IsKey).ToList(), ClientDataInfos = x.Where(y => !y.IsDbGenerated).ToList(), ReturningInfos = x.Where(y => y.IsDbGenerated).ToList() }) .ToList(); info.InsertQueryParts = grouppedByTables.Select(x => { var others = grouppedByTables.Where(y => y.TableName != x.TableName) .SelectMany(y => y.ClientDataInfos) .Select(y => new { My = y, Others = x.ReturningInfos.FirstOrDefault(ri => ri.Property.Name == y.Property.Name) }) .Where(y => y.Others != null) .ToList(); return(new InsertQueryParts() { TableName = x.TableName, TableNameQualified = x.TableNameQualified, TargetColumnNamesQueryPart = string.Join(", ", x.ClientDataInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName))), SourceColumnNamesQueryPart = string.Join(", ", x.ClientDataInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.TempAliasedColumnName))), Returning = string.Join(", ", x.ReturningInfos.Select(y => NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName))), ReturningSetQueryPart = string.Join(", ", others.Select(y => $"{NpgsqlHelper.GetQualifiedName(y.My.TempAliasedColumnName)} " + $" = source.{NpgsqlHelper.GetQualifiedName(y.Others.ColumnInfo.ColumnName)}")) }); }).ToList(); info.SelectSourceForInsertQuery = "SELECT " + string.Join(", ", info.ClientDataInfos .Select(x => $"{x.QualifiedColumnName} AS {x.TempAliasedColumnName}")) + " FROM " + string.Join(", ", grouppedByTables.Select(x => x.TableNameQualified)); info.CopyColumnsForInsertQueryPart = string.Join(", ", info.ClientDataInfos .Select(x => x.TempAliasedColumnName)); info.UpdateQueryParts = grouppedByTables.Select(x => { var updateableInfos = x.ClientDataInfos; updateableInfos = updateableInfos.Where( y => y.ModifierAttributes == null || y.ModifierAttributes.All( m => m.Modification != BulkOperationModification.IgnoreForUpdate) ).ToList(); return(new UpdateQueryParts() { TableName = x.TableName, TableNameQualified = x.TableNameQualified, SetClause = string.Join(", ", updateableInfos.Select(y => { var colName = NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName); return $"{colName} = source.{y.TempAliasedColumnName}"; })), WhereClause = string.Join(" AND ", x.KeyInfos.Select(y => { var colName = NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName); var clause = $"{colName} = source.{y.TempAliasedColumnName}"; if (y.IsNullableInClr) { clause = $"({clause} OR ({colName} IS NULL AND source.{y.TempAliasedColumnName} IS NULL))"; } return clause; })) }); }) .Where(x => !string.IsNullOrEmpty(x.SetClause)) .ToList(); info.SelectSourceForUpdateQuery = "SELECT " + string.Join(", ", info.ClientDataWithKeysInfos .Select(x => $"{x.QualifiedColumnName} AS {x.TempAliasedColumnName}")) + " FROM " + string.Join(", ", grouppedByTables.Select(x => x.TableNameQualified)); info.CopyColumnsForUpdateQueryPart = string.Join(", ", info.ClientDataWithKeysInfos .Select(x => x.TempAliasedColumnName)); info.ClientDataColumnNames = string.Join(", ", info.ClientDataInfos.Select(x => NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName))); info.KeyInfos = info.MappingInfos.Where(x => x.IsKey).ToArray(); info.KeyColumnNames = info.KeyInfos.Select(x => x.ColumnInfo.ColumnName).ToArray(); info.ClientDataWithKeysColumnNames = string.Join(", ", info.ClientDataWithKeysInfos.Select(x => NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName))); info.DbGeneratedInfos = info.MappingInfos.Where(x => x.IsDbGenerated).ToArray(); info.DbGeneratedColumnNames = string.Join(", ", info.DbGeneratedInfos.Select(x => NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName))); if (codeBuilderOuter == null) { codeBuilder.InitBuilder(info, ReadValue); } return(info); }
private string GetTableNameQualified(Type t) { var tableAttr = t.GetCustomAttribute <TableAttribute>(); return(NpgsqlHelper.GetQualifiedName(tableAttr.Name, tableAttr.Schema)); }
private EntityInfo CreateEntityInfo <T>() { var t = typeof(T); var tableName = GetTableName(t); var mappingInfo = GetMappingInfo(t, tableName); var codeBuilder = new NpgsqlBulkCodeBuilder <T>(); var info = new EntityInfo() { TableNameQualified = GetTableNameQualified(t), TableName = tableName, CodeBuilder = codeBuilder, MappingInfos = mappingInfo, TableNames = mappingInfo.Select(x => x.TableName).Distinct().ToArray(), ClientDataInfos = mappingInfo.Where(x => !x.IsDbGenerated).ToArray(), ClientDataWithKeysInfos = mappingInfo.Where(x => !x.IsDbGenerated || x.IsKey).ToArray() }; var grouppedByTables = mappingInfo.GroupBy(x => x.TableName) .Select(x => new { TableName = x.Key, KeyInfos = x.Where(y => y.IsKey).ToList(), ClientDataInfos = x.Where(y => !y.IsDbGenerated).ToList(), ReturningInfos = x.Where(y => y.IsDbGenerated).ToList() }).ToList(); info.InsertQueryParts = grouppedByTables.Select(x => { var others = grouppedByTables.Where(y => y.TableName != x.TableName) .SelectMany(y => y.ClientDataInfos) .Select(y => new { My = y, Others = x.ReturningInfos.FirstOrDefault(ri => ri.Property.Name == y.Property.Name) }) .Where(y => y.Others != null) .ToList(); return(new InsertQueryParts() { TableName = x.TableName, TargetColumnNamesQueryPart = string.Join(", ", x.ClientDataInfos.Select(y => y.ColumnInfo.ColumnName)), SourceColumnNamesQueryPart = string.Join(", ", x.ClientDataInfos.Select(y => y.TempAliasedColumnName)), Returning = string.Join(", ", x.ReturningInfos.Select(y => y.ColumnInfo.ColumnName)), ReturningSetQueryPart = string.Join(", ", others.Select(y => $"{y.My.TempAliasedColumnName} = source.{y.Others.ColumnInfo.ColumnName}")) }); }).ToList(); info.SelectSourceForInsertQuery = "SELECT " + string.Join(", ", info.ClientDataInfos .Select(x => $"{x.QualifiedColumnName} AS {x.TempAliasedColumnName}")) + " FROM " + string.Join(", ", grouppedByTables.Select(x => x.TableName)); info.CopyColumnsForInsertQueryPart = string.Join(", ", info.ClientDataInfos .Select(x => x.TempAliasedColumnName)); info.UpdateQueryParts = grouppedByTables.Select(x => { var updateableInfos = x.ClientDataInfos; updateableInfos = updateableInfos.Where( y => y.ModifierAttributes == null || y.ModifierAttributes.All( m => m.Modification != BulkOperationModification.IgnoreForUpdate) ).ToList(); return(new UpdateQueryParts() { TableName = x.TableName, SetClause = string.Join(", ", updateableInfos.Select(y => { var colName = NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName); return $"{colName} = source.{y.TempAliasedColumnName}"; })), WhereClause = string.Join(", ", x.KeyInfos.Select(y => { var colName = NpgsqlHelper.GetQualifiedName(y.ColumnInfo.ColumnName); return $"{colName} = source.{y.TempAliasedColumnName}"; })) }); }).ToList(); info.SelectSourceForUpdateQuery = "SELECT " + string.Join(", ", info.ClientDataWithKeysInfos .Select(x => $"{x.QualifiedColumnName} AS {x.TempAliasedColumnName}")) + " FROM " + string.Join(", ", grouppedByTables.Select(x => x.TableName)); info.CopyColumnsForUpdateQueryPart = string.Join(", ", info.ClientDataWithKeysInfos .Select(x => x.TempAliasedColumnName)); info.ClientDataColumnNames = string.Join(", ", info.ClientDataInfos.Select(x => NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName))); info.KeyInfos = info.MappingInfos.Where(x => x.IsKey).ToArray(); info.KeyColumnNames = info.KeyInfos.Select(x => x.ColumnInfo.ColumnName).ToArray(); info.ClientDataWithKeysColumnNames = string.Join(", ", info.ClientDataWithKeysInfos.Select(x => NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName))); info.DbGeneratedInfos = info.MappingInfos.Where(x => x.IsDbGenerated).ToArray(); info.DbGeneratedColumnNames = string.Join(", ", info.DbGeneratedInfos.Select(x => NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName))); codeBuilder.InitBuilder(info.ClientDataInfos, info.ClientDataWithKeysInfos, info.DbGeneratedInfos, ReadValue); return(info); }
public static List <T> BulkSelect <T, TKey>( this IQueryable <T> source, Expression <Func <T, TKey> > keyExpression, IEnumerable <TKey> keyData) { EnsureNoNavigationProperties(keyExpression); BulkSelectInterceptor.StartInterception(); var keyDataTable = $"_schema_{DateTime.Now.Ticks}"; var schemaQuery = source.Select(keyExpression); var schemaSql = $"CREATE TEMP TABLE {keyDataTable} ON COMMIT DROP AS ({schemaQuery} LIMIT 0)"; var context = NpgsqlHelper.GetContextFromQuery(source); var conn = NpgsqlHelper.GetNpgsqlConnection(context); var localTr = NpgsqlHelper.EnsureOrStartTransaction(context); try { context.Database.ExecuteSqlCommand(schemaSql); var columnsInfo = NpgsqlHelper.GetColumnsInfo(context, keyDataTable); var propsMap = GetPropertiesMap( ((IObjectContextAdapter)context).ObjectContext, schemaQuery.Expression, typeof(TKey)); var mapsInfo = new List <MappingInfo>(); foreach (var propMap in propsMap) { var cinfo = columnsInfo[propMap.Item2]; mapsInfo.Add(new MappingInfo() { Property = propMap.Item1, ColumnInfo = cinfo, NpgsqlType = NpgsqlBulkUploader.GetNpgsqlType(cinfo) }); } var columnsCsv = string.Join(", ", mapsInfo.Select(x => NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName))); var copySql = $"COPY {keyDataTable} ({columnsCsv}) FROM STDIN (FORMAT BINARY)"; using (var importer = conn.BeginBinaryImport(copySql)) { foreach (var kd in keyData) { importer.StartRow(); foreach (var kp in mapsInfo) { importer.Write(kp.Property.GetValue(kd), kp.NpgsqlType); } } } var whereSql = string.Join(" AND ", mapsInfo.Select(x => $"source.{NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName)}" + $" = {keyDataTable}.{NpgsqlHelper.GetQualifiedName(x.ColumnInfo.ColumnName)}")); var selectSql = $"SELECT source.* FROM ({source}) as source\n" + $"JOIN {keyDataTable} ON {whereSql}"; BulkSelectInterceptor.SetReplaceQuery(source.ToString(), selectSql); var result = source.ToList(); localTr?.Commit(); return(result); } catch { localTr?.Rollback(); throw; } finally { BulkSelectInterceptor.StopInterception(); } }
internal static List <MappingInfo> GetMetadata(DbContext context, Type type) { var metadata = context.Model; var entityType = metadata.GetEntityTypes().Single(x => x.ClrType == type); var tableName = GetTableName(context, type); var columnsInfo = NpgsqlBulkUploader.RelationalHelper.GetColumnsInfo(context, tableName); if (entityType.BaseType != null) { var baseTableName = GetTableName(context, entityType.BaseType.ClrType); if (baseTableName != tableName) { var extraColumnsInfo = NpgsqlBulkUploader.RelationalHelper.GetColumnsInfo(context, baseTableName); columnsInfo.AddRange(extraColumnsInfo); } } var valueGenSelector = ((IInfrastructure <IServiceProvider>)context).Instance.GetService <IValueGeneratorSelector>(); int optinalIndex = 0; var innerList = entityType .GetProperties() .Where(x => x.GetColumnName() != "xmin") // For now we don't support xmin .Select(x => { var relational = x.DeclaringEntityType; ValueGenerator localGenerator = null; bool isDbGenerated = false; var generatorFactory = x.GetAnnotations().FirstOrDefault(a => a.Name == "ValueGeneratorFactory"); if (generatorFactory != null) { var valueGeneratorAccessor = generatorFactory.Value as Func <IProperty, IEntityType, ValueGenerator>; localGenerator = valueGeneratorAccessor(x, x.DeclaringEntityType); } else if (x.GetAnnotations().Any(y => y.Name == "Relational:ComputedColumnSql")) { isDbGenerated = true; } else { var autoGenStrategy = x.GetAnnotations().FirstOrDefault(y => y.Name == "Npgsql:ValueGenerationStrategy"); if (autoGenStrategy != null) { var npgsqlStartegy = (NpgsqlValueGenerationStrategy)autoGenStrategy.Value; isDbGenerated = npgsqlStartegy != NpgsqlValueGenerationStrategy.SequenceHiLo && npgsqlStartegy != NpgsqlValueGenerationStrategy.None; } } if (!isDbGenerated && localGenerator == null) { try { localGenerator = valueGenSelector.Select(x, entityType); } catch { // ignore } } #if DotNet6 var readBack = x.GetStoreGeneratedIndex() >= 0; #else var indexes = ((Microsoft.EntityFrameworkCore.Metadata.Internal.Property)x).PropertyIndexes; var readBack = indexes.StoreGenerationIndex >= 0; #endif long optionalFlag = 0; // We don't support genertion based on Foreign Keys. if (readBack && !x.IsForeignKey() && localGenerator == null) { optionalFlag = 1 << optinalIndex; optinalIndex++; } return(new MappingInfo() { TableName = relational.GetTableName(), TableNameQualified = NpgsqlHelper.GetQualifiedName(relational.GetTableName(), relational.GetSchema()), Property = x.PropertyInfo, ColumnInfo = columnsInfo.First(c => c.ColumnName == x.GetColumnName()), LocalGenerator = localGenerator, ValueConverter = x.GetValueConverter(), IsKey = x.IsKey(), IsInheritanceUsed = entityType.BaseType != null, DbProperty = x, DoUpdate = !isDbGenerated && x.PropertyInfo != null, // don't update shadow props DoInsert = !isDbGenerated, // do insert of shadow props ReadBack = readBack, IsSpecifiedFlag = optionalFlag }); }).ToList(); return(innerList); }