[#79] AppDbContext: Use compiled queries

This commit is contained in:
2026-04-04 15:28:30 +02:00
parent 9c39a2f820
commit d051a2bfcf
42 changed files with 393 additions and 379 deletions

View File

@@ -56,9 +56,9 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(" ")[0], a => a);
var attrId = await ctx.WineAttributes.ToDictionaryAsync(a => a.AttrId, a => a);
var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attrId = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var attr = attrId.Values.ToDictionary(a => a.Name.ToLower().Split(" ")[0], a => a);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];

View File

@@ -65,11 +65,11 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];

View File

@@ -60,8 +60,8 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];
@@ -174,12 +174,12 @@ namespace Elwig.Services {
ctx.Add(s);
}
ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties
await ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties
.Where(v => v.Year == s.Year && v.DsNr == s.DsNr)
.Select(v => new { v.Variety, v.Priority })
.ToListAsync())
.Select(v => (v.Variety, v.Priority))
.ToList(), vm.MainVarieties.Select(v => (v, 1)).Union(vm.OtherVarieties.Select(v => (v, 2))).ToList());
.Select(v => (v.Variety.SortId, v.Priority))
.ToList(), vm.MainVarieties.Select(v => (v.SortId, 1)).Union(vm.OtherVarieties.Select(v => (v.SortId, 2))).ToList());
await ctx.SaveChangesAsync();
});

View File

@@ -27,7 +27,7 @@ namespace Elwig.Services {
public static async Task<Member?> GetMemberAsync(int mgnr) {
using var ctx = new AppDbContext();
return await ctx.Members.FirstOrDefaultAsync(m => m.MgNr == mgnr);
return await ctx.FetchMembers(mgnr).SingleOrDefaultAsync();
}
public static Member? GetMember(int mgnr) {
@@ -126,12 +126,12 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var qual = await ctx.WineQualityLevels.Where(q => !q.IsPredicate).ToDictionaryAsync(q => q.QualId, q => q);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var qual = await ctx.FetchWineQualityLevels(false).ToDictionaryAsync(q => q.QualId, q => q);
var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];
@@ -546,14 +546,14 @@ namespace Elwig.Services {
ctx.Add(p);
}
ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers
await ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers
.Where(m => m.Year == p.Year && m.DId == p.DId && m.DPNr == p.DPNr)
.Select(m => m.Modifier)
.ToListAsync(), vm.Modifiers);
.Select(m => m.ModId)
.ToListAsync(), vm.Modifiers.Select(m => m.ModId).ToList());
if (originalMgNr != null && originalMgNr.Value != d.MgNr) {
// update origin (KgNr), if default is selected
var newKgNr = (await ctx.Members.FindAsync(d.MgNr))?.DefaultKgNr;
var newKgNr = (await ctx.FetchMembers(d.MgNr).SingleOrDefaultAsync())?.DefaultKgNr;
await ctx.DeliveryParts
.Where(p => p.Year == d.Year && p.DId == d.DId && p.DPNr != dpnr && p.KgNr == originalMemberKgNr)
.ExecuteUpdateAsync(u => u.SetProperty(p => p.KgNr, newKgNr));
@@ -637,7 +637,7 @@ namespace Elwig.Services {
Delivery n;
using var ctx = new AppDbContext();
var anyLeft = false;
n = (await ctx.Deliveries.FirstAsync(d => d.LsNr == lsnr))!;
n = (await ctx.Deliveries.Where(d => d.LsNr == lsnr).FirstAsync())!;
var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
@@ -951,7 +951,7 @@ namespace Elwig.Services {
tblTotal.FullName = DeliveryDepreciationList.Name;
tblTotal.Name = "Gesamt";
await ods.AddTable(tblTotal);
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) {
foreach (var branch in await ctx.FetchBranches().ToListAsync()) {
var tbl = await DeliveryJournalData.FromQuery(query.Where(p => p.Delivery.ZwstId == branch.ZwstId), filterNames);
tbl.FullName = DeliveryDepreciationList.Name;
tbl.Name = branch.Name;
@@ -1062,16 +1062,23 @@ namespace Elwig.Services {
var gGrid = new List<(string?, string?, double, double, double)>();
var gText = "-";
var weight = await deliveryParts.SumAsync(p => p.Weight);
wText = $"{weight:N0} kg";
wGrid.Add(("Menge", null, weight, null, weight));
var stat = (await deliveryParts.GroupBy(p => 0)
.Select(g => new {
Weight = g.Sum(p => p.Weight),
Min = g.Select(p => (double?)p.Kmw).DefaultIfEmpty().Min(),
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
Max = g.Select(p => (double?)p.Kmw).DefaultIfEmpty().Max(),
})
.ToListAsync())
.DefaultIfEmpty(new { Weight = 0, Min = (double?)null, Avg = (double)0, Max = (double?)null })
.Single();
if (await deliveryParts.AnyAsync()) {
var kmwMin = await deliveryParts.MinAsync(p => p.Kmw);
var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts);
var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw);
gText = $"{kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°";
gGrid.Add(("Gradation", null, kmwMin, kmwAvg, kmwMax));
wText = $"{stat.Weight:N0} kg";
wGrid.Add(("Menge", null, stat.Weight, null, stat.Weight));
if (stat.Min != null && stat.Max != null) {
gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°";
gGrid.Add(("Gradation", null, stat.Min.Value, stat.Avg, stat.Max.Value));
var attrGroups = await deliveryParts
.GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name })
@@ -1122,9 +1129,9 @@ namespace Elwig.Services {
foreach (var attrG in attrGroups) {
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
wGrid.Add((name, null, attrG.Weight, attrG.Weight, weight));
wGrid.Add((name, null, attrG.Weight, attrG.Weight, stat.Weight));
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, weight));
wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, stat.Weight));
}
}
foreach (var attrG in attrGroups) {
@@ -1143,12 +1150,12 @@ namespace Elwig.Services {
gText += $" [{name}]";
}
if (sortGroups.Count > 1 && sortGroups.Count <= 4) {
wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
gText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
}
} else if (attrGroups.Count <= 4) {
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
}
}

View File

@@ -172,7 +172,7 @@ namespace Elwig.Services {
var c = m.ActiveAreaCommitments(ctx, Utils.CurrentLastSeason);
int maxKgPerHa = 10_000;
try {
var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year));
var s = await ctx.FetchSeasons().FirstOrDefaultAsync();
if (s != null) maxKgPerHa = s.MaxKgPerHa;
} catch { }
var (text, gridData) = await AreaComService.GenerateToolTipData(c, maxKgPerHa);
@@ -225,8 +225,8 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var branches = await ctx.Branches.ToListAsync();
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var branches = await ctx.FetchBranches().ToListAsync();
var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var kgs = await ctx.WbKgs.ToDictionaryAsync(k => k.AtKg.Name.ToLower(), k => k.AtKg);
var areaComs = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => $"{t.SortId}{t.AttrId}", t => t);
@@ -408,7 +408,7 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = new Billing(year);
var b = await Billing.Create(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
@@ -708,7 +708,7 @@ namespace Elwig.Services {
await Task.Run(async () => {
using var ctx = new AppDbContext();
using var tx = await ctx.Database.BeginTransactionAsync();
var l = (await ctx.Members.FindAsync(mgnr))!;
var l = await ctx.FetchMembers(mgnr).SingleAsync();
if (deletePaymentData) {
await ctx.Credits.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
}

View File

@@ -363,21 +363,21 @@ namespace Elwig.Services {
public static async Task Calculate(int year, int avnr) {
await Task.Run(async () => {
var b = new BillingVariant(year, avnr);
var b = await BillingVariant.Create(year, avnr);
await b.Calculate();
});
}
public static async Task Commit(int year, int avnr) {
await Task.Run(async () => {
var b = new BillingVariant(year, avnr);
var b = await BillingVariant.Create(year, avnr);
await b.Commit();
});
}
public static async Task Revert(int year, int avnr) {
await Task.Run(async () => {
var b = new BillingVariant(year, avnr);
var b = await BillingVariant.Create(year, avnr);
await b.Revert();
});
}

View File

@@ -258,7 +258,7 @@ namespace Elwig.Services {
public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password) {
try {
return await ctx.Members.AnyAsync(ChangedMembers) || await ctx.AreaCommitmentContracts.AnyAsync(ChangedAreaComContracts) || await ctx.Deliveries.AnyAsync(ChangedDeliveries) || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
return await ctx.Members.Where(ChangedMembers).AnyAsync() || await ctx.AreaCommitmentContracts.Where(ChangedAreaComContracts).AnyAsync() || await ctx.Deliveries.Where(ChangedDeliveries).AnyAsync() || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
} catch {
return false;
}