指定使用实体框架核心处理两个连接表(以前处理过多对多)的多对多

时间:2019-02-11 05:35:31

标签: c# sql entity-framework asp.net-core entity-framework-core

我从来没有遇到过最初解决两个多对多问题的情况。但是接下来,这两个连接表又是多对多的。我想知道是否有更好的方法来构造带有实体框架核心的对象。这就是我得到的。我试图找出哪些项目所有者是哪些项目产品的一部分。

我有3张桌子:

项目
产品
所有者

一个项目可以有许多产品,而一个项目可以有许多所有者。一个产品可以有多个项目,而所有者可以有多个项目。通过执行以下操作,我解决了这两个多对多关系:

ProjectProduct
两个键:ProjectId,ProductId

项目所有者
两个键:ProjectId,OwnerId

另外,一个ProjectProduct可以有许多ProjectOwner,而一个ProjectOwner可以有许多ProjectsProduct。

我认为解决方案是向ProjectOwner和ProjectProduct添加一个唯一的ID,并使用以下键创建一个名为 ProjectProductOwner 的新实体:
ProjectProductId,ProjectOwnerId

这是我的DBContext的样子:

// Key Specifications
modelBuilder.Entity<ProjectProductOwner>()
    .HasKey(x => new { x.ProjectProductId, x.ProjectOwnerId });

// Project Product
modelBuilder.Entity<ProjectProduct>()
    .HasOne(x => x.Project)
    .WithMany(x => x.Products)
    .HasForeignKey(x => x.ProjectId);

modelBuilder.Entity<ProjectProduct>()
    .HasOne(x => x.Product)
    .WithMany(x => x.Projects)
    .HasForeignKey(x => x.ProductId);

// Project Owner
modelBuilder.Entity<ProjectOwner>()
    .HasOne(x => x.Project)
    .WithMany(x => x.Owners)
    .HasForeignKey(x => x.ProjectId);

modelBuilder.Entity<ProjectOwner>()
    .HasOne(x => x.Owner)
    .WithMany(x => Projects)
    .HasForeignKey(x => x.OwnerId);

// Project Product Owner
modelBuilder.Entity<ProjectProductOwner>()
    .HasOne(x => x.ProjectProduct)
    .WithMany(x => x.ProjectOwners)
    .HasForeignKey(x => x.ProjectProductId);

modelBuilder.Entity<ProjectProductOwner>()
    .HasOne(x => x.ProjectOwner)
    .WithMany(x => x.ProjectProducts)
    .HasForeignKey(x => x.ProjectOwnerId);  

我遇到了错误: 在表'ProjectProductOwner'上引入FOREIGN KEY约束'FK_ProjectProductOwner_ProjectProducts_ProjectProductId'可能会导致循环或多个级联路径。

另外:

表“ ProjectProductOwner”上的“ FK_ProjectProductOwner_ProjectOwners_ProjectOwnerId”可能会导致循环或多个级联路径。

1 个答案:

答案 0 :(得分:1)

您可以将ProjectProductProjectProductOwner“合并”到一个表中。由于您先将Owners添加到Project中,然后为Products中的每个Owner添加一个或多个Project,所以我不需要第三个多对多实体,从而简化了它:)

注意:我什至不理会这个错误,因为正如您所说并我同意,大多数情况下这些错误会在您的模型不正确时出现。

Owner

public class Owner
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<ProjectOwner> ProjectOwners { get; set; }
    public ICollection<ProjectProductOwner> ProjectProductOwners { get; set; }
}

Product

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<ProjectProductOwner> ProjectProductOwners { get; set; }
}

Project and many-to-many tables

public class Project
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<ProjectOwner> ProjectOwners { get; set; }
    public ICollection<ProjectProductOwner> ProjectProductOwners { get; set; }

    public Project()
    {
        ProjectOwners = new List<ProjectOwner>();
        ProjectProductOwners = new List<ProjectProductOwner>();
    }
}

public class ProjectOwner
{
    public int OwnerId { get; set; }
    public Owner Owner { get; set; }
    public int ProjectId { get; set; }
    public Project Project { get; set; }
}

public class ProjectProductOwner
{
    public int ProductId { get; set; }
    public Product Product { get; set; }
    public int OwnerId { get; set; }
    public Owner Owner { get; set; }
    public int ProjectId { get; set; }
    public Project Project { get; set; }
}

DbContext配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // Configure Owners in a Project
    modelBuilder.Entity<ProjectOwner>()
        .HasKey(p => new { p.ProjectId, p.OwnerId });

    modelBuilder.Entity<ProjectOwner>()
        .HasOne(bc => bc.Project)
        .WithMany(b => b.ProjectOwners)
        .HasForeignKey(bc => bc.ProjectId);

    modelBuilder.Entity<ProjectOwner>()
        .HasOne(bc => bc.Owner)
        .WithMany(c => c.ProjectOwners)
        .HasForeignKey(bc => bc.OwnerId);

    // Configure Products for each owner in a Project
    modelBuilder.Entity<ProjectProductOwner>()
        .HasKey(p => new { p.ProjectId, p.ProductId, p.OwnerId });

    modelBuilder.Entity<ProjectProductOwner>()
        .HasOne(bc => bc.Project)
        .WithMany(b => b.ProjectProductOwners)
        .HasForeignKey(bc => bc.ProjectId);

    modelBuilder.Entity<ProjectProductOwner>()
        .HasOne(bc => bc.Product)
        .WithMany(c => c.ProjectProductOwners)
        .HasForeignKey(bc => bc.ProductId);

    modelBuilder.Entity<ProjectProductOwner>()
        .HasOne(bc => bc.Owner)
        .WithMany(c => c.ProjectProductOwners)
        .HasForeignKey(bc => bc.OwnerId);
}

最后,您可以添加新项目并使用以下查询它:

using (var db = new ProjectContext())
{
    var project = new Project();
    project.Name = "My project";

    // assumes there's 3 owners and 2 products already inserted in the DB

    // Add the 3 owners to the project
    project.ProjectOwners.Add(new ProjectOwner { OwnerId = 1});
    project.ProjectOwners.Add(new ProjectOwner { OwnerId = 2});
    project.ProjectOwners.Add(new ProjectOwner { OwnerId = 3});

    // Add Product 1 to Owner 1 and 2
    project.ProjectProductOwners.Add(new ProjectProductOwner { ProductId = 1, OwnerId = 1 });
    project.ProjectProductOwners.Add(new ProjectProductOwner { ProductId = 1, OwnerId = 2 });

    // Add Product 2 to Owner 1 and 3
    project.ProjectProductOwners.Add(new ProjectProductOwner { ProductId = 2, OwnerId = 1 });
    project.ProjectProductOwners.Add(new ProjectProductOwner { ProductId = 2, OwnerId = 3 });

    db.Add(project);
    db.SaveChanges();

    var projects = db.Project
        .Include(p => p.ProjectOwners)
        .ThenInclude(p => p.Owner)
        .Include(p => p.ProjectProductOwners)
        .ThenInclude(p => p.Product)
        .FirstOrDefault();
}