代码之家  ›  专栏  ›  技术社区  ›  Blake Rivell

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

  •  1
  • Blake Rivell  · 技术社区  · 6 年前

    我从来没有遇到过我最初有两个多对多问题得到解决的情况。但在另一个层次上,这两个联接表上都有另一个多对多的连接。我想知道是否有更好的方法来构建这个w/实体框架核心。这是我得到的。我试图找出哪些项目所有者是哪些项目产品的一部分。

    我有三张桌子:

    项目

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


    两个键:ProjectId、ProductId

    项目所有者

    此外,一个项目产品可以有多个项目所有者,一个项目所有者可以有多个项目产品。

    项目产品所有者 使用以下键:
    ProjectProductId,ProjectOwnerId

    // 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”上引入外键约束“FK_ProjectProductOwner\u ProjectProducts\u ProjectProductId”可能会导致循环或多个级联路径。

    此外:

    1 回复  |  直到 6 年前
        1
  •  1
  •   jpgrassi    6 年前

    您可以“合并”该文件 ProjectProduct ProjectProductOwner 坐在一张桌子上。既然你加了 Owners Project 首先,然后添加一个或多个 Products 每人 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();
    }
    
    推荐文章