[英]EF Core Unique Constraint across multiple tables
如何创建/设计关系和唯一约束:
一个项目有许多SUBJOBS。 SUBJOB有许多任务。 任务具有一个编号,该编号在单个项目中必须唯一。
我为关系尝试了以下方法,但是我不知道如何对Task.Number
和Project.ProjectId
实施唯一约束:
public class ProjectContext : DbContext
{
public DbSet<Project> Project { get; private set; }
public DbSet<SubJob> SubJob { get; private set; }
public DbSet<Task> Task { get; private set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Project>(b =>
{
b.HasKey(p => p.ProjectId);
b.HasAlternateKey(p => p.Code);
});
modelBuilder.Entity<SubJob>(b =>
{
b.HasKey(s => s.SubJobId);
b.HasOne(s => s.Project).WithMany(p => p.SubJobs).HasForeignKey(s => s.ProjectId);
b.HasAlternateKey(s => new { s.ProjectId, s.Code });
});
modelBuilder.Entity<Task>(b =>
{
b.HasKey(l => l.TaskId);
b.HasOne(l => l.SubJob).WithMany(s => s.Tasks).HasForeignKey(l => l.SubJobId);
});
}
}
public class Project
{
public int ProjectId { get; private set; }
public string Code { get; set; }
public ICollection<SubJob> SubJobs { get; private set; } = new List<SubJob>();
}
public class SubJob
{
public int SubJobId { get; private set; }
public int ProjectId { get; private set; }
public Project Project { get; set; }
public string Code { get; set; }
public ICollection<Task> Tasks { get; private set; } = new List<Task>();
}
public class Task
{
public int TaskId { get; private set; }
public int SubJobId { get; private set; }
public SubJob SubJob { get; set; }
public int Number { get; set; }
}
我看到两种可能性。 对子类使用自然键,因此Subjob可能是{ProjectId,JobCode},而Task可能是{ProjectId,JobCode,Number}。 但是,如果{ProjectId,Number}必须是唯一的,那么它将是PK,而JobCode将是非空FK,但不是PK的一部分。
或者,如果数据库支持索引视图,则可以在{ProjectId,Number}上创建具有唯一索引的视图。
要在Tasks
表上定义唯一约束,您需要在Task
类中获取ProjectId
值。 修改后的Task
实体看起来像这样。
public class Task
{
public int TaskId { get; private set; }
public int SubJobId { get; private set; }
public SubJob SubJob { get; set; }
public int Number { get; set; }
public int ProjectId { get; set; } // Added property
}
由于每个Task
都有一个SubJob
,每个SubJob
都有一个Project
, Task.ProjectId
应该等于Task.SubJob.ProjectId
(后者从SubJob.Project.ProjectId
获取值)。 为了确保传递此值,我们可以定义Task
和SubJob
之间的关系以使用复合键,如下所示
modelBuilder.Entity<Task>(b =>
{
b.HasKey(l => l.TaskId);
b.HasOne(l => l.SubJob).WithMany(s => s.Tasks).HasForeignKey(l => new { l.SubJobId, l.ProjectId })
.HasPrincipalKey(l => new { l.SubJobId, l.ProjectId });
b.HasAlternateKey(t => new { t.Number, t.ProjectId });
});
然后,我们可以使用HasAlternateKey
在Number
& ProjectId
定义唯一约束。
您也可以使用带有ProjectId
复合键,但是这可能需要为PK的其他部分设置值生成。
除非您确实需要唯一约束,否则请考虑使用唯一索引。 更多信息可以在这里找到
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.