Improved Performance of sql queries related to articles
This commit is contained in:
parent
cdd1490801
commit
04bea51271
|
@ -164,25 +164,22 @@
|
|||
}
|
||||
|
||||
protected override void OnInitialized() {
|
||||
using var context = ContextFactory.CreateDbContext();
|
||||
var query = context.Set<Article>()
|
||||
.IgnoreQueryFilters().Where(a => !a.IsDeleted)
|
||||
.Include(a => a.Author)
|
||||
.Include(a => a.Reviewer)
|
||||
.Include(a => a.Categories);
|
||||
|
||||
// We need blocking calls here, bc otherwise Blazor will execute Render in parallel,
|
||||
// running into a null pointer on the Article property and panicking
|
||||
if (Id is not null) {
|
||||
using var context = ContextFactory.CreateDbContext();
|
||||
Article = context.Set<Article>()
|
||||
.IgnoreQueryFilters().Where(a => !a.IsDeleted)
|
||||
.Include(a => a.Author)
|
||||
.Include(a => a.Reviewer)
|
||||
.Include(a => a.Categories)
|
||||
.FirstOrDefault(a => a.Id == Id);
|
||||
Article = query.AsSingleQuery().FirstOrDefault(a => a.Id == Id);
|
||||
} else if (Date is { } date && Title is { } title) {
|
||||
using var context = ContextFactory.CreateDbContext();
|
||||
string? slug = TitleEncoded == null ? null : Uri.EscapeDataString(TitleEncoded);
|
||||
Article ??= context.Set<Article>()
|
||||
.IgnoreQueryFilters().Where(a => !a.IsDeleted)
|
||||
.Include(a => a.Author)
|
||||
.Include(a => a.Reviewer)
|
||||
.Include(a => a.Categories)
|
||||
.FirstOrDefault(a => a.PublishDate.Date == date.Date && (slug != null && a.Slug == slug || a.Title.ToLower() == title));
|
||||
Article = query.AsSingleQuery().FirstOrDefault(a =>
|
||||
a.PublishDate.Date == date.Date
|
||||
&& (slug != null && a.Slug == slug || a.Title.ToLower() == title));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,10 +42,22 @@
|
|||
protected override async Task OnInitializedAsync() {
|
||||
await using var context = await ContextFactory.CreateDbContextAsync();
|
||||
string category = WebUtility.UrlDecode(CategoryName);
|
||||
await context.Set<Category>().LoadAsync();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
// First load Category with simple chain and manual filters, as to minimize
|
||||
// filter redundancy and query complexity (category -> Articles -> Author is linear)
|
||||
Category = await context.Set<Category>()
|
||||
.Include(c => c.Articles).ThenInclude(a => a.Author)
|
||||
.Include(c => c.Articles).ThenInclude(a => a.Categories)
|
||||
.IgnoreAutoIncludes().IgnoreQueryFilters()
|
||||
.Include(c => c.Articles.Where(a => !a.IsDeleted && a.PublishDate <= now))
|
||||
.ThenInclude(a => a.Author)
|
||||
.FirstOrDefaultAsync(c => c.Name == category);
|
||||
// Load all the other categories missing on the articles, by loading all relevant
|
||||
// articles ID with their categories, so EF can map them to the already loaded entries
|
||||
// (again manual filter to minimize redundancy)
|
||||
await context.Set<Article>()
|
||||
.IgnoreAutoIncludes().IgnoreQueryFilters()
|
||||
.Where(a => !a.IsDeleted && a.PublishDate <= now && a.Categories.Contains(Category!))
|
||||
.Select(a => new {
|
||||
a.Id, a.Categories
|
||||
}).LoadAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,11 +161,14 @@
|
|||
try {
|
||||
await using var context = await ContextFactory.CreateDbContextAsync();
|
||||
|
||||
var query = context.Set<Article>()
|
||||
.Include(a => a.Author).Include(a => a.Categories)
|
||||
.OrderByDescending(a => a.PublishDate).ThenBy(a => a.Id);
|
||||
var query = context.Set<Article>();
|
||||
|
||||
Featured = await query.FirstOrDefaultAsync();
|
||||
Featured = await query
|
||||
.Include(a => a.Author)
|
||||
.Include(a => a.Categories)
|
||||
.OrderByDescending(a => a.PublishDate).ThenBy(a => a.Id)
|
||||
.AsSplitQuery()
|
||||
.FirstOrDefaultAsync();
|
||||
TotalPages = (int) Math.Max(Math.Ceiling((await query.CountAsync() - 1) / 10.0), 1);
|
||||
} catch {
|
||||
Message.ShowError(Localizer["Articles_Load_Error"]);
|
||||
|
@ -178,6 +181,7 @@
|
|||
return await context.Set<Article>()
|
||||
.Include(a => a.Author).Include(a => a.Categories)
|
||||
.OrderByDescending(a => a.PublishDate).ThenBy(a => a.Id)
|
||||
.AsSplitQuery()
|
||||
.Skip(page + 1).Take(count).ToListAsync();
|
||||
} catch {
|
||||
Message.ShowError(Localizer["Articles_Load_Error"]);
|
||||
|
|
|
@ -93,13 +93,20 @@
|
|||
|
||||
// Find user
|
||||
if (Id is not null) {
|
||||
User = await context.Users.Include(u => u.Articles)
|
||||
.ThenInclude(a => a.Categories)
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
User = await context.Users
|
||||
.IgnoreAutoIncludes().IgnoreQueryFilters()
|
||||
.Include(u => u.Articles.Where(a => !a.IsDeleted && a.PublishDate <= now))
|
||||
.FirstOrDefaultAsync(u => u.Id == Id.ToString());
|
||||
await context.Set<Article>()
|
||||
.Where(a => a.Author.Id == Id.ToString())
|
||||
.Select(a => new {
|
||||
a.Id, a.Categories
|
||||
}).LoadAsync();
|
||||
}
|
||||
|
||||
// Validate access to user
|
||||
if (User is not null && User.Articles.Count > 0) {
|
||||
if (User is not null && (User.Articles.Count > 0 || HttpContext.User.IsInRole("Admin"))) {
|
||||
} else if (User is not null && HttpContext.User.FindFirst("Id")?.Value == User.Id) {
|
||||
Message.ShowWarning(Localizer["ProfileNotPublic_Message"]);
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue