【发布时间】:2021-01-05 00:07:07
【问题描述】:
我试图在我的模型中实现以下关系(简化)。换句话说,每个Employee 可以有多个银行Accounts(私人账户、公司账户等)。每个员工都可以携带任何与公司相关的Receipt(例如煤气费、警察罚款等)。现在,根据这张收据的总价值,公司可以决定他们是否会立即向用户收取这个价值,或者,如果这是大量的钱,他们需要每月扣除(因此每张收据可以有多个Transactions在这种情况下被理解为扣除)。如果立即对Receipt 收费(请参阅模型上的ReceiptType 属性),则此实体仅存在一个Transaction。最后(特别是在长期扣除的情况下),Transaction 需要访问Account,因为我们需要指定,这个值将被记入哪个员工的帐户。
这是我指定实体的方式:
public class EmployeeDB
{
public long Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public virtual IEnumerable<EmployeeAccountDB> Accounts { get; set; }
public virtual IEnumerable<ReceiptDB> Receipts { get; set; }
}
public class EmployeeAccountDB
{
public long Id { get; set; }
public long EmployeeId { get; set; }
public virtual EmployeeDB Employee { get; set; }
public virtual IEnumerable<TransactionDB> Transactions { get; set; }
}
public class ReceiptDB
{
public long Id { get; set; }
public long EmployeeDBId { get; set; }
public ReceiptTypeEnum ReceiptType { get; set; }
public double Value { get; set; }
public double VAT { get; set; }
public double TotalValue { get; set; }
public virtual EmployeeDB Employee { get; set; }
public virtual IEnumerable<TransactionDB> Transactions { get; set; }
}
public class TransactionDB
{
public long Id { get; set; }
public long EmployeeAccountId { get; set; }
public long ReceiptDBId { get; set; }
public virtual ReceiptDB Receipt { get; set; }
public virtual EmployeeAccountDB Account { get; set; }
}
现在我通过 Fluent API 指定了以下实体配置:
public class EmployeeDBConfiguration : IEntityTypeConfiguration<EmployeeDB>
{
public void Configure(EntityTypeBuilder<EmployeeDB> builder)
{
builder.ToTable("Employees", ApplicationDbContext.DefaultSchema);
builder.HasKey(t => t.Id);
builder.Property(t => t.HireDate).IsRequired();
builder.HasMany(x => x.Accounts).WithOne(x => x.Employee).OnDelete(DeleteBehavior.Cascade);
builder.HasMany(x => x.Receipts).WithOne(x => x.Employee).OnDelete(DeleteBehavior.Cascade);
}
}
public class EmployeeAccountDBConfiguration : IEntityTypeConfiguration<EmployeeAccountDB>
{
public void Configure(EntityTypeBuilder<EmployeeAccountDB> builder)
{
builder.ToTable("EmployeeAccounts", ApplicationDbContext.DefaultSchema);
builder.HasKey(t => t.Id);
builder.Property(t => t.Id).ValueGeneratedOnAdd();
builder.HasOne(x => x.Employee).WithMany(o => o.Accounts).HasForeignKey(nameof(EmployeeAccountDB.EmployeeId));
builder.HasMany(x => x.Transactions).WithOne(x => x.Account).OnDelete(DeleteBehavior.Cascade);
}
}
public class ReceiptDBConfiguration : IEntityTypeConfiguration<ReceiptDB>
{
public void Configure(EntityTypeBuilder<ReceiptDB> builder)
{
builder.ToTable("Receipts", ApplicationDbContext.DefaultSchema);
builder.HasKey(t => t.Id);
builder.Property(t => t.Id).ValueGeneratedOnAdd();
builder.Property(t => t.TotalValue).IsRequired();
builder.HasOne(x => x.Employee).WithMany(x=>x.Receipts).HasForeignKey(x => x.EmployeeDBId);
builder.HasMany(x => x.Transactions).WithOne(x => x.Receipt).OnDelete(DeleteBehavior.Cascade);
}
}
class TransactionDBConfiguration : IEntityTypeConfiguration<TransactionDB>
{
public void Configure(EntityTypeBuilder<TransactionDB> builder)
{
builder.ToTable("Transactions", ApplicationDbContext.DefaultSchema);
builder.HasKey(t => t.Id);
builder.Property(t => t.Id).ValueGeneratedOnAdd();
}
}
迁移创建得很好。但是,当我尝试通过dotnet ef database update 创建数据库时,就会出现问题。我遇到以下问题
引入 FOREIGN KEY 约束 表“事务”上的“FK_Transactions_Receipts_ReceiptDBId”可能 导致循环或多级联路径
我不确定真正的问题是什么。我的目标是(我试图设置的)当Employee 被删除时,与该实体相关的所有后续实体Account、Receipt、Transaction 也将被删除(如配置中指定的 >级联删除)。
我们将非常感谢您就此事提供任何帮助。如果我的模型结构不正确,我很乐意对其进行重构以使其保持简单和干净。
附:我正在连接 SQL 数据库。
【问题讨论】:
-
看看stackoverflow.com/questions/27792131/…。 SQL Server 无法处理删除链。一个出路是使用逻辑删除在每个类中设置一个
public bool IsActive {get;set;} -
这可能与以下内容重复:stackoverflow.com/questions/851625/…
-
收据是否只记入一个帐户?如果收据与与员工关联的帐户(或与帐户关联的交易)相关联,为什么收据会链接到员工?
-
收据未与账户相关联,因为交易负责从账户中扣款。收据只是有关特定账单或发票的信息的持有者。但是 Receipt 应该包含有关 Employee 的信息,以防我们需要显示与 Employee 关联的所有 Receipts
-
所以收据和交易不相关?
标签: c# sql database-design ef-core-3.1