简体   繁体   English

跨多个表的EF核心唯一约束

[英]EF Core Unique Constraint across multiple tables

How do I create/design the relationship and unique constraint: 如何创建/设计关系和唯一约束:

A PROJECT has many SUBJOBS. 一个项目有许多SUBJOBS。 A SUBJOB has many TASKS. SUBJOB有许多任务。 A TASK has a Number which must be unique across a single PROJECT. 任务具有一个编号,该编号在单个项目中必须唯一。

I tried the following for the relationship but I can't figure out how to enforce the unique constraint for Task.Number and Project.ProjectId : 我为关系尝试了以下方法,但是我不知道如何对Task.NumberProject.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; }
}

I see two possibilities. 我看到两种可能性。 Use natural keys for the child classes, so Subjob might be {ProjectId, JobCode} and Task might be {ProjectId, JobCode, Number}. 对子类使用自然键,因此Subjob可能是{ProjectId,JobCode},而Task可能是{ProjectId,JobCode,Number}。 But if the {ProjectId, Number} must be unique, then that would be the PK and JobCode would be a non-null FK, but not part of the PK. 但是,如果{ProjectId,Number}必须是唯一的,那么它将是PK,而JobCode将是非空FK,但不是PK的一部分。

Or, if your database supports indexed views you could create a view with a unique index on {ProjectId, Number}. 或者,如果数据库支持索引视图,则可以在{ProjectId,Number}上创建具有唯一索引的视图。

To define unique constraint on Tasks table, you would need to get value of ProjectId in Task class. 要在Tasks表上定义唯一约束,您需要在Task类中获取ProjectId值。 The modified Task entity would look like this. 修改后的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
}

Since every Task has a SubJob and every SubJob has a Project , Task.ProjectId should be equal to Task.SubJob.ProjectId (which in turn takes value from SubJob.Project.ProjectId ). 由于每个Task都有一个SubJob ,每个SubJob都有一个ProjectTask.ProjectId应该等于Task.SubJob.ProjectId (后者从SubJob.Project.ProjectId获取值)。 To make sure this value is passed around we can define a relationship between Task & SubJob to use composite keys like following 为了确保传递此值,我们可以定义TaskSubJob之间的关系以使用复合键,如下所示

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 });
});

Then we can define the unique constraint over Number & ProjectId using HasAlternateKey . 然后,我们可以使用HasAlternateKeyNumberProjectId定义唯一约束。

You could also use Composite Keys with ProjectId as being part but that could require to setup value generation for other part of PK. 您也可以使用带有ProjectId复合键,但是这可能需要为PK的其他部分设置值生成。

Unless you really need unique constraint, consider using unique index. 除非您确实需要唯一约束,否则请考虑使用唯一索引。 More info can be found here 更多信息可以在这里找到

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM