refactor built query with less mem allocation.

This commit is contained in:
Фролов 2021-11-17 10:52:03 +05:00
parent db0b430d93
commit 361aceed96
2 changed files with 51 additions and 28 deletions

View File

@ -13,7 +13,7 @@ namespace AsbCloudDb
{
static Dictionary<Type, IQueryStringFactory> QueryFactories { get; set; } = new Dictionary<Type, IQueryStringFactory>();
static IQueryStringFactory GetQueryStringFactory<T>(DbSet<T> dbset)
static QueryStringFactory<T> GetQueryStringFactory<T>(DbSet<T> dbset)
where T : class
{
var t = typeof(T);
@ -30,8 +30,9 @@ namespace AsbCloudDb
public static Task<int> ExecInsertOrUpdateAsync<T>(this Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade database, DbSet<T> dbset, IEnumerable<T> items, CancellationToken token)
where T : class
{
var factory = (QueryStringFactory<T>)GetQueryStringFactory(dbset);
var factory = GetQueryStringFactory(dbset);
var query = factory.MakeInsertOrUpdateSql(items);
return database.ExecuteSqlRawAsync(query, token);
}
}
@ -41,10 +42,11 @@ namespace AsbCloudDb
class QueryStringFactory<T> : 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<IClrPropertyGetter> getters;
public QueryStringFactory(DbSet<T> 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<T> 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<T> items)
private StringBuilder BuildRows(StringBuilder builder, IEnumerable<T> 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)

View File

@ -18,7 +18,27 @@ namespace ConsoleApp1
class Program
{
static void Main(/*string[] args*/)
{
{
//var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
// .UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
// .Options;
//var context = new AsbCloudDbContext(options);
//var sett = context.Set<TelemetryDataSaub>();
//var r = context.Database.ExecInsertOrUpdateAsync(sett, new List<TelemetryDataSaub> {
// 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();
}
}