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

时间:2018-04-04 21:23:21

标签: sql database database-design entity-framework-core

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

项目有很多SUBJOBS。 SUBJOB有许多任务。任务有一个数字,在一个PROJECT中必须是唯一的。

我尝试了以下关系,但我无法弄清楚如何强制执行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; }
}

2 个答案:

答案 0 :(得分:1)

我看到两种可能性。对子类使用自然键,因此Subjob可能是{ProjectId,JobCode},Task可能是{ProjectId,JobCode,Number}。但是如果{ProjectId,Number}必须是唯一的,那么那就是PK而JobCode将是一个非空的FK,但不是PK的一部分。

或者,如果您的数据库支持索引视图,则可以在{ProjectId,Number}上创建具有唯一索引的视图。

答案 1 :(得分:0)

要在Tasks表上定义唯一约束,您需要在ProjectId类中获取Task的值。修改后的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取值Task)。为了确保传递这个值,我们可以定义SubJob和&amp;之间的关系。 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 }); }); 使用复合键,如下面的

Number

然后我们可以在ProjectId&amp;上定义唯一约束。 HasAlternateKey使用ProjectId

您也可以使用 let accessoryButton = UIButton(type: .roundedRect) accessoryButton.setTitle("message", for: .normal) accessoryButton.sizeToFit() accessoryButton.addTarget(self, action: #selector(goToMessaging(sender:)), for: UIControlEvents.touchUpInside) cell.accessoryView = accessoryButton as UIView @objc func goToMessaging(sender: UIButton){ print("message him") } 作为其中一部分的复合键,但这可能需要为PK的其他部分设置值生成。

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

找到