forked from ddrilling/AsbCloudServer
refactor built query with less mem allocation.
This commit is contained in:
parent
db0b430d93
commit
361aceed96
@ -13,7 +13,7 @@ namespace AsbCloudDb
|
|||||||
{
|
{
|
||||||
static Dictionary<Type, IQueryStringFactory> QueryFactories { get; set; } = new Dictionary<Type, IQueryStringFactory>();
|
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
|
where T : class
|
||||||
{
|
{
|
||||||
var t = typeof(T);
|
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)
|
public static Task<int> ExecInsertOrUpdateAsync<T>(this Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade database, DbSet<T> dbset, IEnumerable<T> items, CancellationToken token)
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
var factory = (QueryStringFactory<T>)GetQueryStringFactory(dbset);
|
var factory = GetQueryStringFactory(dbset);
|
||||||
var query = factory.MakeInsertOrUpdateSql(items);
|
var query = factory.MakeInsertOrUpdateSql(items);
|
||||||
|
|
||||||
return database.ExecuteSqlRawAsync(query, token);
|
return database.ExecuteSqlRawAsync(query, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,10 +42,11 @@ namespace AsbCloudDb
|
|||||||
class QueryStringFactory<T> : IQueryStringFactory
|
class QueryStringFactory<T> : IQueryStringFactory
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
|
private readonly string insertHeader;
|
||||||
|
|
||||||
private readonly string pk;
|
private readonly string pk;
|
||||||
private readonly string tableName;
|
private readonly string tableName;
|
||||||
private readonly string colunmsString;
|
private readonly string conflictBody;
|
||||||
private readonly string conflictUpdateSet;
|
|
||||||
private readonly IEnumerable<IClrPropertyGetter> getters;
|
private readonly IEnumerable<IClrPropertyGetter> getters;
|
||||||
|
|
||||||
public QueryStringFactory(DbSet<T> dbset)
|
public QueryStringFactory(DbSet<T> dbset)
|
||||||
@ -56,8 +58,11 @@ namespace AsbCloudDb
|
|||||||
tableName = dbset.EntityType.GetTableName();
|
tableName = dbset.EntityType.GetTableName();
|
||||||
getters = ps.Select(p => p.GetGetter());
|
getters = ps.Select(p => p.GetGetter());
|
||||||
var colNames = ps.Select(p => $"\"{p.GetColumnBaseName()}\"");
|
var colNames = ps.Select(p => $"\"{p.GetColumnBaseName()}\"");
|
||||||
colunmsString = $"({string.Join(", ", colNames)})";
|
var colunmsString = $"({string.Join(", ", colNames)})";
|
||||||
conflictUpdateSet = string.Join(", ", colNames.Select(n => $"{n} = excluded.{n}"));
|
|
||||||
|
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)
|
public string MakeInsertOrUpdateSql(IEnumerable<T> items)
|
||||||
@ -69,37 +74,35 @@ namespace AsbCloudDb
|
|||||||
SET column_1 = excluded.column_1,
|
SET column_1 = excluded.column_1,
|
||||||
column_2 = excluded.column_2;
|
column_2 = excluded.column_2;
|
||||||
*/
|
*/
|
||||||
var sqlBuilder = new StringBuilder("INSERT INTO ", 7);
|
var builder = new StringBuilder(insertHeader, 7);
|
||||||
sqlBuilder.Append(tableName);
|
BuildRows(builder, items);
|
||||||
sqlBuilder.Append(colunmsString);
|
|
||||||
sqlBuilder.AppendLine(" VALUES ");
|
|
||||||
sqlBuilder.Append(MakeQueryValues(items));
|
|
||||||
sqlBuilder.AppendLine(" ON CONFLICT ");
|
|
||||||
if (string.IsNullOrEmpty(pk))
|
if (string.IsNullOrEmpty(pk))
|
||||||
{
|
builder.Append(" ON CONFLICT DO NOTHING;");
|
||||||
sqlBuilder.Append("DO NOTHING;");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
builder.AppendLine(conflictBody);
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private StringBuilder BuildRows(StringBuilder builder, IEnumerable<T> items)
|
||||||
{
|
{
|
||||||
sqlBuilder.Append(pk);
|
var list = items.ToList();
|
||||||
sqlBuilder.Append(" DO UPDATE SET ");
|
for (int i = 0; i < list.Count; i++)
|
||||||
sqlBuilder.AppendLine(conflictUpdateSet);
|
|
||||||
sqlBuilder.Append(';');
|
|
||||||
}
|
|
||||||
|
|
||||||
return sqlBuilder.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string MakeQueryValues(IEnumerable<T> items)
|
|
||||||
{
|
{
|
||||||
var rows = items.Select(item => MakeRow(item));
|
if(i > 0)
|
||||||
return string.Join(",", rows);
|
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)));
|
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)
|
private static string FormatValue(object v)
|
||||||
|
@ -19,6 +19,26 @@ namespace ConsoleApp1
|
|||||||
{
|
{
|
||||||
static void Main(/*string[] args*/)
|
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();
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user