250 lines
8.9 KiB
C#
250 lines
8.9 KiB
C#
|
|
using Microsoft.EntityFrameworkCore;
|
||
|
|
using HardwarePerformance.Core.Entities;
|
||
|
|
|
||
|
|
namespace HardwarePerformance.Infrastructure.Data
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 应用程序数据库上下文
|
||
|
|
/// </summary>
|
||
|
|
public class AppDbContext : DbContext
|
||
|
|
{
|
||
|
|
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
// DbSets
|
||
|
|
public DbSet<Category> Categories { get; set; }
|
||
|
|
public DbSet<Product> Products { get; set; }
|
||
|
|
public DbSet<PerformanceScore> PerformanceScores { get; set; }
|
||
|
|
public DbSet<Specification> Specifications { get; set; }
|
||
|
|
public DbSet<DataSource> DataSources { get; set; }
|
||
|
|
public DbSet<RankingHistory> RankingHistories { get; set; }
|
||
|
|
|
||
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||
|
|
{
|
||
|
|
base.OnModelCreating(modelBuilder);
|
||
|
|
|
||
|
|
// 配置Category实体
|
||
|
|
modelBuilder.Entity<Category>(entity =>
|
||
|
|
{
|
||
|
|
entity.HasKey(e => e.Id);
|
||
|
|
|
||
|
|
entity.Property(e => e.Name)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(100);
|
||
|
|
|
||
|
|
entity.Property(e => e.Description)
|
||
|
|
.HasMaxLength(500);
|
||
|
|
|
||
|
|
entity.Property(e => e.IconUrl)
|
||
|
|
.HasMaxLength(500);
|
||
|
|
|
||
|
|
entity.Property(e => e.CreatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
entity.Property(e => e.UpdatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
entity.HasIndex(e => e.Name).IsUnique();
|
||
|
|
entity.HasIndex(e => e.SortOrder);
|
||
|
|
});
|
||
|
|
|
||
|
|
// 配置Product实体
|
||
|
|
modelBuilder.Entity<Product>(entity =>
|
||
|
|
{
|
||
|
|
entity.HasKey(e => e.Id);
|
||
|
|
|
||
|
|
entity.Property(e => e.Name)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(200);
|
||
|
|
|
||
|
|
entity.Property(e => e.Model)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(200);
|
||
|
|
|
||
|
|
entity.Property(e => e.Manufacturer)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(100);
|
||
|
|
|
||
|
|
entity.Property(e => e.ImageUrl)
|
||
|
|
.HasMaxLength(500);
|
||
|
|
|
||
|
|
entity.Property(e => e.Description)
|
||
|
|
.HasMaxLength(2000);
|
||
|
|
|
||
|
|
entity.Property(e => e.CreatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
entity.Property(e => e.UpdatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
// 配置外键关系
|
||
|
|
entity.HasOne(e => e.Category)
|
||
|
|
.WithMany(c => c.Products)
|
||
|
|
.HasForeignKey(e => e.CategoryId)
|
||
|
|
.OnDelete(DeleteBehavior.Cascade);
|
||
|
|
|
||
|
|
// 配置索引
|
||
|
|
entity.HasIndex(e => e.Name);
|
||
|
|
entity.HasIndex(e => e.Model);
|
||
|
|
entity.HasIndex(e => e.CategoryId);
|
||
|
|
entity.HasIndex(e => e.PerformanceScore);
|
||
|
|
entity.HasIndex(e => e.CurrentRank);
|
||
|
|
entity.HasIndex(e => e.Manufacturer);
|
||
|
|
entity.HasIndex(e => e.ReleaseYear);
|
||
|
|
entity.HasIndex(e => new { e.CategoryId, e.CurrentRank });
|
||
|
|
});
|
||
|
|
|
||
|
|
// 配置PerformanceScore实体
|
||
|
|
modelBuilder.Entity<PerformanceScore>(entity =>
|
||
|
|
{
|
||
|
|
entity.HasKey(e => e.Id);
|
||
|
|
|
||
|
|
entity.Property(e => e.TestName)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(100);
|
||
|
|
|
||
|
|
entity.Property(e => e.Unit)
|
||
|
|
.HasMaxLength(20);
|
||
|
|
|
||
|
|
entity.Property(e => e.TestVersion)
|
||
|
|
.HasMaxLength(50);
|
||
|
|
|
||
|
|
entity.Property(e => e.CreatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
// 配置外键关系
|
||
|
|
entity.HasOne(e => e.Product)
|
||
|
|
.WithMany(p => p.PerformanceScores)
|
||
|
|
.HasForeignKey(e => e.ProductId)
|
||
|
|
.OnDelete(DeleteBehavior.Cascade);
|
||
|
|
|
||
|
|
entity.HasOne(e => e.DataSource)
|
||
|
|
.WithMany(d => d.PerformanceScores)
|
||
|
|
.HasForeignKey(e => e.DataSourceId)
|
||
|
|
.OnDelete(DeleteBehavior.Restrict);
|
||
|
|
|
||
|
|
// 配置索引
|
||
|
|
entity.HasIndex(e => new { e.ProductId, e.TestName });
|
||
|
|
entity.HasIndex(e => e.Score);
|
||
|
|
entity.HasIndex(e => e.TestDate);
|
||
|
|
});
|
||
|
|
|
||
|
|
// 配置Specification实体
|
||
|
|
modelBuilder.Entity<Specification>(entity =>
|
||
|
|
{
|
||
|
|
entity.HasKey(e => e.Id);
|
||
|
|
|
||
|
|
entity.Property(e => e.GroupName)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(100);
|
||
|
|
|
||
|
|
entity.Property(e => e.Name)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(100);
|
||
|
|
|
||
|
|
entity.Property(e => e.Value)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(500);
|
||
|
|
|
||
|
|
entity.Property(e => e.Unit)
|
||
|
|
.HasMaxLength(20);
|
||
|
|
|
||
|
|
entity.Property(e => e.CreatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
entity.Property(e => e.UpdatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
// 配置外键关系
|
||
|
|
entity.HasOne(e => e.Product)
|
||
|
|
.WithMany(p => p.Specifications)
|
||
|
|
.HasForeignKey(e => e.ProductId)
|
||
|
|
.OnDelete(DeleteBehavior.Cascade);
|
||
|
|
|
||
|
|
// 配置索引
|
||
|
|
entity.HasIndex(e => new { e.ProductId, e.GroupName });
|
||
|
|
entity.HasIndex(e => new { e.ProductId, e.Name });
|
||
|
|
entity.HasIndex(e => e.IsKeySpecification);
|
||
|
|
});
|
||
|
|
|
||
|
|
// 配置DataSource实体
|
||
|
|
modelBuilder.Entity<DataSource>(entity =>
|
||
|
|
{
|
||
|
|
entity.HasKey(e => e.Id);
|
||
|
|
|
||
|
|
entity.Property(e => e.Name)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(100);
|
||
|
|
|
||
|
|
entity.Property(e => e.Description)
|
||
|
|
.HasMaxLength(500);
|
||
|
|
|
||
|
|
entity.Property(e => e.Url)
|
||
|
|
.HasMaxLength(500);
|
||
|
|
|
||
|
|
entity.Property(e => e.Type)
|
||
|
|
.IsRequired()
|
||
|
|
.HasMaxLength(50);
|
||
|
|
|
||
|
|
entity.Property(e => e.CreatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
entity.Property(e => e.UpdatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
// 配置索引
|
||
|
|
entity.HasIndex(e => e.Name).IsUnique();
|
||
|
|
entity.HasIndex(e => e.Type);
|
||
|
|
});
|
||
|
|
|
||
|
|
// 配置RankingHistory实体
|
||
|
|
modelBuilder.Entity<RankingHistory>(entity =>
|
||
|
|
{
|
||
|
|
entity.HasKey(e => e.Id);
|
||
|
|
|
||
|
|
entity.Property(e => e.CreatedAt)
|
||
|
|
.HasDefaultValueSql("UTC_TIMESTAMP()");
|
||
|
|
|
||
|
|
// 配置外键关系
|
||
|
|
entity.HasOne(e => e.Product)
|
||
|
|
.WithMany(p => p.RankingHistories)
|
||
|
|
.HasForeignKey(e => e.ProductId)
|
||
|
|
.OnDelete(DeleteBehavior.Cascade);
|
||
|
|
|
||
|
|
// 配置索引
|
||
|
|
entity.HasIndex(e => new { e.ProductId, e.RecordDate });
|
||
|
|
entity.HasIndex(e => e.Rank);
|
||
|
|
entity.HasIndex(e => e.RecordDate);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
public override int SaveChanges()
|
||
|
|
{
|
||
|
|
UpdateTimestamps();
|
||
|
|
return base.SaveChanges();
|
||
|
|
}
|
||
|
|
|
||
|
|
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
||
|
|
{
|
||
|
|
UpdateTimestamps();
|
||
|
|
return base.SaveChangesAsync(cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void UpdateTimestamps()
|
||
|
|
{
|
||
|
|
var entries = ChangeTracker.Entries()
|
||
|
|
.Where(e => e.Entity is BaseEntity && (e.State == EntityState.Added || e.State == EntityState.Modified));
|
||
|
|
|
||
|
|
foreach (var entry in entries)
|
||
|
|
{
|
||
|
|
if (entry.State == EntityState.Added)
|
||
|
|
{
|
||
|
|
((BaseEntity)entry.Entity).CreatedAt = DateTime.UtcNow;
|
||
|
|
}
|
||
|
|
|
||
|
|
((BaseEntity)entry.Entity).UpdatedAt = DateTime.UtcNow;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|