private EntityInfo CreateEntityInfo <T>(IEnumerable <PropertyInfo> props) { var t = typeof(T); var tableName = NpgsqlHelper.GetTableName(context, t); var mappingInfo = GetMappingInfo(t, tableName); var tableNameQualified = NpgsqlHelper.GetTableNameQualified(context, t); // filter by props var keyProps = mappingInfo.Where(x => x.IsKey).Select(x => x.Property); var propToInfo = mappingInfo.ToDictionary(x => x.Property); mappingInfo = props.Union(keyProps).Select(x => propToInfo[x]).ToList(); // key for partial coe builder var propNames = typeof(T).FullName + "_" + string.Join("_", props.Select(x => $"{x.DeclaringType.Name}_{x.Name}")); NpgsqlBulkCodeBuilder <T> codeBuilder; if (partialCodeBuilders.TryGetValue(propNames, out object cb)) { codeBuilder = (NpgsqlBulkCodeBuilder <T>)cb; return(CreateEntityInfo <T>(tableName, tableNameQualified, mappingInfo, codeBuilder)); } else { codeBuilder = new NpgsqlBulkCodeBuilder <T>(); var info = CreateEntityInfo <T>(tableName, tableNameQualified, mappingInfo, codeBuilder); codeBuilder.InitBuilder(info, ReadValue); partialCodeBuilders.TryAdd(propNames, codeBuilder); return(info); } }
private void SetAutoGeneratedFields <T>( IEnumerable <T> entities, EntityInfo infos, NpgsqlBulkCodeBuilder <T> codeBuilders, EntityState state) { if (infos.PropertyNameToGenerators == null || infos.PropertyNameToGenerators.Count == 0) { return; } var sm = ((IDbContextDependencies)context).StateManager; foreach (var item in entities) { var entry = sm.TryGetEntry(item); if (entry == null) { entry = sm.GetOrCreateEntry(item); entry.SetEntityState(EntityState.Added); //codeBuilders.AutoGenerateValues( // item, new Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry(entry), infos.PropertyNameToGenerators); } } }
private void WriteInsertPortion <T>( IEnumerable <T> list, EntityInfo mapping, NpgsqlConnection conn, string tempTableName, NpgsqlBulkCodeBuilder <T> codeBuilder) { // 2. Import into temp table using (var importer = conn.BeginBinaryImport($"COPY {tempTableName} ({mapping.CopyColumnsForInsertQueryPart}, __index) FROM STDIN (FORMAT BINARY)")) { var opContext = new OperationContext(context, false); var index = 1; foreach (var item in list) { importer.StartRow(); codeBuilder.WriterForInsertAction(item, importer, opContext); importer.Write(index, NpgsqlDbType.Integer); index++; } // Temp solution!!! //importer.Complete(); CompleteMethodInfo.Invoke(importer, null); } }
private void SetAutoGeneratedFields <T>( IEnumerable <T> entities, EntityInfo infos, NpgsqlBulkCodeBuilder <T> codeBuilders) { if (infos.PropertyNameToGenerators == null || infos.PropertyNameToGenerators.Count == 0) { return; } #pragma warning disable EF1001 // Internal EF Core API usage. var sm = ((IDbContextDependencies)context).StateManager; #pragma warning restore EF1001 // Internal EF Core API usage. foreach (var item in entities) { #pragma warning disable EF1001 // Internal EF Core API usage. var entry = sm.TryGetEntry(item); #pragma warning restore EF1001 // Internal EF Core API usage. if (entry == null) { #pragma warning disable EF1001 // Internal EF Core API usage. entry = sm.GetOrCreateEntry(item); #pragma warning restore EF1001 // Internal EF Core API usage. codeBuilders.AutoGenerateValues( #pragma warning disable EF1001 // Internal EF Core API usage. item, new Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry(entry), infos.PropertyNameToGenerators); #pragma warning restore EF1001 // Internal EF Core API usage. } } }
private async Task InsertPortionAsync <T>( IEnumerable <T> list, List <InsertQueryParts> insertParts, NpgsqlConnection conn, NpgsqlBulkCodeBuilder <T> codeBuilder, string tempTableName, object ignoreDuplicatesStatement, InsertConflictAction onConflict) { // 3. Insert into real table from temp one foreach (var insertPart in insertParts) { using (var cmd = conn.CreateCommand()) { var baseInsertCmd = $"INSERT INTO {insertPart.TableNameQualified} ({insertPart.TargetColumnNamesQueryPart}) " + $"SELECT {insertPart.SourceColumnNamesQueryPart} FROM {tempTableName} ORDER BY __index {ignoreDuplicatesStatement}"; if (string.IsNullOrEmpty(insertPart.ReturningSetQueryPart)) { cmd.CommandText = baseInsertCmd; if (!string.IsNullOrEmpty(insertPart.Returning)) { cmd.CommandText = $"WITH inserted as (\n {baseInsertCmd} RETURNING {insertPart.Returning} \n ), \n"; cmd.CommandText += $"source as (\n SELECT *, ROW_NUMBER() OVER (ORDER BY {insertPart.Returning}) as __index FROM inserted \n ) \n"; cmd.CommandText += $"SELECT * FROM source ORDER BY __index"; } } else { cmd.CommandText = $"WITH inserted as (\n {baseInsertCmd} RETURNING {insertPart.Returning} \n ), \n"; cmd.CommandText += $"source as (\n SELECT *, ROW_NUMBER() OVER (ORDER BY {insertPart.Returning}) as __index FROM inserted \n ) \n"; cmd.CommandText += $"UPDATE {tempTableName} SET {insertPart.ReturningSetQueryPart} FROM source WHERE {tempTableName}.__index = source.__index\n"; cmd.CommandText += $"RETURNING {insertPart.Returning}"; } using (var reader = (NpgsqlDataReader)(await cmd.ExecuteReaderAsync())) { // 4. Propagate computed value if (!string.IsNullOrEmpty(insertPart.Returning)) { if (onConflict == null) { var readAction = codeBuilder.InsertIdentityValuesWriterActions[insertPart.TableName]; foreach (var item in list) { await reader.ReadAsync(); readAction(item, reader); } } else { while (await reader.ReadAsync()) { // do nothing, for now... } } } } } } }
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); }
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 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); }