From 361aceed96cb942aca8c887bdc47a81113ff1f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A4=D1=80=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Wed, 17 Nov 2021 10:52:03 +0500 Subject: [PATCH] refactor built query with less mem allocation. --- AsbCloudDb/EFExtentions.cs | 57 ++++++++++++++++++++------------------ ConsoleApp1/Program.cs | 22 ++++++++++++++- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/AsbCloudDb/EFExtentions.cs b/AsbCloudDb/EFExtentions.cs index 1490e747..d3c78bd5 100644 --- a/AsbCloudDb/EFExtentions.cs +++ b/AsbCloudDb/EFExtentions.cs @@ -13,7 +13,7 @@ namespace AsbCloudDb { static Dictionary QueryFactories { get; set; } = new Dictionary(); - static IQueryStringFactory GetQueryStringFactory(DbSet dbset) + static QueryStringFactory GetQueryStringFactory(DbSet dbset) where T : class { var t = typeof(T); @@ -30,8 +30,9 @@ namespace AsbCloudDb public static Task ExecInsertOrUpdateAsync(this Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade database, DbSet dbset, IEnumerable items, CancellationToken token) where T : class { - var factory = (QueryStringFactory)GetQueryStringFactory(dbset); + var factory = GetQueryStringFactory(dbset); var query = factory.MakeInsertOrUpdateSql(items); + return database.ExecuteSqlRawAsync(query, token); } } @@ -41,10 +42,11 @@ namespace AsbCloudDb class QueryStringFactory : IQueryStringFactory where T : class { + private readonly string insertHeader; + private readonly string pk; private readonly string tableName; - private readonly string colunmsString; - private readonly string conflictUpdateSet; + private readonly string conflictBody; private readonly IEnumerable getters; public QueryStringFactory(DbSet dbset) @@ -56,8 +58,11 @@ namespace AsbCloudDb tableName = dbset.EntityType.GetTableName(); getters = ps.Select(p => p.GetGetter()); var colNames = ps.Select(p => $"\"{p.GetColumnBaseName()}\""); - colunmsString = $"({string.Join(", ", colNames)})"; - conflictUpdateSet = string.Join(", ", colNames.Select(n => $"{n} = excluded.{n}")); + var colunmsString = $"({string.Join(", ", colNames)})"; + + insertHeader = $"INSERT INTO {tableName} {colunmsString} VALUES "; + var excludedUpdateSet = string.Join(", ", colNames.Select(n => $"{n} = excluded.{n}")); + conflictBody = $" ON CONFLICT {pk} DO UPDATE SET {excludedUpdateSet};"; } public string MakeInsertOrUpdateSql(IEnumerable items) @@ -69,37 +74,35 @@ namespace AsbCloudDb SET column_1 = excluded.column_1, column_2 = excluded.column_2; */ - var sqlBuilder = new StringBuilder("INSERT INTO ", 7); - sqlBuilder.Append(tableName); - sqlBuilder.Append(colunmsString); - sqlBuilder.AppendLine(" VALUES "); - sqlBuilder.Append(MakeQueryValues(items)); - sqlBuilder.AppendLine(" ON CONFLICT "); + var builder = new StringBuilder(insertHeader, 7); + BuildRows(builder, items); if (string.IsNullOrEmpty(pk)) - { - sqlBuilder.Append("DO NOTHING;"); - } + builder.Append(" ON CONFLICT DO NOTHING;"); else - { - sqlBuilder.Append(pk); - sqlBuilder.Append(" DO UPDATE SET "); - sqlBuilder.AppendLine(conflictUpdateSet); - sqlBuilder.Append(';'); - } + builder.AppendLine(conflictBody); - return sqlBuilder.ToString(); + return builder.ToString(); } - private string MakeQueryValues(IEnumerable items) + private StringBuilder BuildRows(StringBuilder builder, IEnumerable items) { - var rows = items.Select(item => MakeRow(item)); - return string.Join(",", rows); + var list = items.ToList(); + for (int i = 0; i < list.Count; i++) + { + if(i > 0) + builder.Append(','); + BuildRow(builder, list[i]); + } + return builder; } - private string MakeRow(T item) + private StringBuilder BuildRow(StringBuilder builder, T item) { var values = getters.Select(getter => FormatValue(getter.GetClrValue(item))); - return $"({string.Join(",", values)})"; + builder.Append('('); + builder.AppendJoin(",", values); + builder.Append(')'); + return builder; } private static string FormatValue(object v) diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs index f23cdd81..34f609ec 100644 --- a/ConsoleApp1/Program.cs +++ b/ConsoleApp1/Program.cs @@ -18,7 +18,27 @@ namespace ConsoleApp1 class Program { static void Main(/*string[] args*/) - { + { + //var options = new DbContextOptionsBuilder() + // .UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True") + // .Options; + //var context = new AsbCloudDbContext(options); + + //var sett = context.Set(); + //var r = context.Database.ExecInsertOrUpdateAsync(sett, new List { + // new TelemetryDataSaub + // { + // Date = DateTime.Now, + // IdTelemetry = 3, + // AxialLoad = 100.1f, + // }, + // new TelemetryDataSaub + // { + // Date = DateTime.Now.AddSeconds(2), + // IdTelemetry = 3, + // AxialLoad = 100.2f, + // }, + //}, System.Threading.CancellationToken.None).Result; Console.ReadKey(); } }