我从来没有遇到过最初解决两个多对多问题的情况。但是接下来,这两个连接表又是多对多的。我想知道是否有更好的方法来构造带有实体框架核心的对象。这就是我得到的。我试图找出哪些项目所有者是哪些项目产品的一部分。
我有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”可能会导致循环或多个级联路径。
答案 0 :(得分:1)
您可以将ProjectProduct
与ProjectProductOwner
“合并”到一个表中。由于您先将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();
}