繁体   English   中英

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

[英]EF Core Unique Constraint across multiple tables

如何创建/设计关系和唯一约束:

一个项目有许多SUBJOBS。 SUBJOB有许多任务。 任务具有一个编号,该编号在单个项目中必须唯一。

我为关系尝试了以下方法,但是我不知道如何对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; }
}

我看到两种可能性。 对子类使用自然键,因此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都有一个ProjectTask.ProjectId应该等于Task.SubJob.ProjectId (后者从SubJob.Project.ProjectId获取值)。 为了确保传递此值,我们可以定义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 });
});

然后,我们可以使用HasAlternateKeyNumberProjectId定义唯一约束。

您也可以使用带有ProjectId复合键,但是这可能需要为PK的其他部分设置值生成。

除非您确实需要唯一约束,否则请考虑使用唯一索引。 更多信息可以在这里找到

暂无
暂无

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

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