|
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace CatalogDb;
public record Catalog(int FirstId, int NextId, bool IsLastPage, IEnumerable<CatalogItem> Data);
public class CatalogDbContext(DbContextOptions<CatalogDbContext> options) : DbContext(options)
{
// https://learn.microsoft.com/ef/core/performance/advanced-performance-topics#compiled-queries
private static readonly Func<CatalogDbContext, int?, int?, int?, int, IAsyncEnumerable<CatalogItem>> s_getCatalogItemsQuery =
EF.CompileAsyncQuery((CatalogDbContext context, int? catalogBrandId, int? before, int? after, int pageSize) =>
context.CatalogItems.AsNoTracking()
.OrderBy(ci => ci.Id)
.Where(ci => catalogBrandId == null || ci.CatalogBrandId == catalogBrandId)
.Where(ci => before == null || ci.Id <= before)
.Where(ci => after == null || ci.Id >= after)
.Take(pageSize + 1));
public Task<List<CatalogItem>> GetCatalogItemsCompiledAsync(int? catalogBrandId, int? before, int? after, int pageSize)
{
return ToListAsync(s_getCatalogItemsQuery(this, catalogBrandId, before, after, pageSize));
}
public DbSet<CatalogItem> CatalogItems => Set<CatalogItem>();
public DbSet<CatalogBrand> CatalogBrands => Set<CatalogBrand>();
public DbSet<CatalogType> CatalogTypes => Set<CatalogType>();
protected override void OnModelCreating(ModelBuilder builder)
{
DefineCatalogBrand(builder.Entity<CatalogBrand>());
DefineCatalogItem(builder.Entity<CatalogItem>());
DefineCatalogType(builder.Entity<CatalogType>());
}
private static void DefineCatalogType(EntityTypeBuilder<CatalogType> builder)
{
builder.ToTable("CatalogType");
builder.HasKey(ci => ci.Id);
builder.Property(ci => ci.Id)
.UseHiLo("catalog_type_hilo")
.IsRequired();
builder.Property(cb => cb.Type)
.IsRequired()
.HasMaxLength(100);
}
private static void DefineCatalogItem(EntityTypeBuilder<CatalogItem> builder)
{
builder.ToTable("Catalog");
builder.Property(ci => ci.Id)
.UseHiLo("catalog_hilo")
.IsRequired();
builder.Property(ci => ci.Name)
.IsRequired(true)
.HasMaxLength(50);
builder.Property(ci => ci.Price)
.IsRequired(true);
builder.Property(ci => ci.PictureFileName)
.IsRequired(false);
builder.Ignore(ci => ci.PictureUri);
builder.HasOne(ci => ci.CatalogBrand)
.WithMany()
.HasForeignKey(ci => ci.CatalogBrandId);
builder.HasOne(ci => ci.CatalogType)
.WithMany()
.HasForeignKey(ci => ci.CatalogTypeId);
}
private static void DefineCatalogBrand(EntityTypeBuilder<CatalogBrand> builder)
{
builder.ToTable("CatalogBrand");
builder.HasKey(ci => ci.Id);
builder.Property(ci => ci.Id)
.UseHiLo("catalog_brand_hilo")
.IsRequired();
builder.Property(cb => cb.Brand)
.IsRequired()
.HasMaxLength(100);
}
private static async Task<List<T>> ToListAsync<T>(IAsyncEnumerable<T> asyncEnumerable)
{
var results = new List<T>();
await foreach (var value in asyncEnumerable)
{
results.Add(value);
}
return results;
}
}
public class CatalogType
{
public int Id { get; set; }
public required string Type { get; set; }
}
public class CatalogBrand
{
public int Id { get; set; }
public required string Brand { get; set; }
}
public class CatalogItem
{
public int Id { get; set; }
public required string Name { get; set; }
public string? Description { get; set; }
public decimal Price { get; set; }
public required string PictureFileName { get; set; }
public string? PictureUri { get; set; }
public int CatalogTypeId { get; set; }
public required CatalogType CatalogType { get; set; }
public int CatalogBrandId { get; set; }
public required CatalogBrand CatalogBrand { get; set; }
public int AvailableStock { get; set; }
public int RestockThreshold { get; set; }
public int MaxStockThreshold { get; set; }
public bool OnReorder { get; set; }
}
|