[英]Entity Framework (Core), multiple refrences to the same table but different objects
I have an automotive part: 我有一个汽车零件:
CREATE TABLE dbo.Part (
Id int IDENTITY(1,1) not null,
PartNumber nvarchar(48) not null,
Colour nvarchar(100) null,
Height int null,
-- etc
)
Automotive parts are often interchangeable. 汽车零件通常是可互换的。 You can replace 1 part on your car/truck with OEM part "A" or aftermarket part "B".
您可以将汽车/卡车上的1个零件替换为OEM零件“ A”或配件市场零件“ B”。
CREATE TABLE dbo.Interchanges (
Part1 int not null,
Part2 int not null,
Notes nvarchar(500) not null,
)
ALTER TABLE dbo.Interchanges WITH CHECK ADD CONSTRAINT fk_Interchanges_Part1
FOREIGN KEY (Part1) REFERENCES dbo.Part (Id)
ALTER TABLE dbo.Interchanges WITH CHECK ADD CONSTRAINT fk_Interchanges_Part2
FOREIGN KEY (Part2) REFERENCES dbo.Part (Id)
Note: 1 part can be interchanged with many other parts, and interchanges are two-way in this case. 注意:1个部分可以与许多其他部分互换,在这种情况下,互换是双向的。
Now let's pretend I've two parts (part number A, and B), and they are interchanged with one another. 现在,假设我有两个部分(零件号A和B),并且它们彼此互换。
When I instantiate part A I'd like it to have a collection of Interchanges. 当我实例化A部分时,我希望它具有一组Interchanges。 In this case the collection would have one object.
在这种情况下,集合将只有一个对象。 That object would have the interchange notes and a part object instance whose part number is B.
该对象将具有交换注释和零件编号为B的零件对象实例。
Similarly, if I edit part B, it's collection would have an object which has the interchange notes and a part instance whose part number is A. 同样,如果我编辑零件B,则其集合中将有一个对象,该对象具有互换注释和零件实例,零件编号为A。
Is there an elegant way to model this? 有没有一种优雅的方式对此建模?
Is there a name for this pattern that I can Google? Google可以为这种模式命名吗?
With the SQL above when I load part A it has a ICollection (created with the Entity Framework Power Tools addon). 使用上面的SQL,当我加载部件A时,它具有一个ICollection(使用Entity Framework Power Tools插件创建)。 That interchange object has the interchange notes, an instance of Part B, and also an instance of Part A.
该交换对象具有交换注释,B部分的实例以及A部分的实例。
In the relational model there's no first-class way to model a Symmetric Relation , so you either have to handle it in application code, or store it as two separate rows (A,B, 'A and B are interchangable') and (B,A, 'A and B are interchangable') 在关系模型中,没有一流的方法来为对称关系建模,因此您要么必须在应用程序代码中对其进行处理,要么将其存储为两个单独的行(A,B,“ A和B可互换”)和(B ,A,“ A和B可互换”)
If you add rows for the inverse of each relation, then the EF model is simple, as Part only needs one Navigation Property. 如果为每个关系的倒数添加行,则EF模型很简单,因为零件仅需要一个导航属性。
Here's a Code First model version of what (I think) you are looking for: 这是您正在寻找的代码优先模型版本:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
namespace ConsoleApp6
{
public class Part
{
public int Id { get; set; }
public string PartNumber { get; set; }
public string Colour { get; set; }
public int Height { get; set; }
public virtual ICollection<Interchange> Interchanges { get; } = new HashSet<Interchange>();
}
public class Interchange
{
[Key]
[Column(Order =1 )]
public int FromPartId { get; set; }
[Key]
[Column(Order = 2)]
public int ToPartId { get; set; }
public virtual Part FromPart { get; set; }
public virtual Part ToPart { get; set; }
}
class Db : DbContext
{
public DbSet<Part> Parts { get; set; }
public DbSet<Interchange> Interchanges { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Part>()
.HasMany(p => p.Interchanges)
.WithRequired()
.HasForeignKey(i => i.FromPartId)
.WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<Db>());
using (var db = new Db())
{
db.Database.Log = a => Console.WriteLine(a);
var A = db.Parts.Create();
A.PartNumber = "A";
var B = db.Parts.Create();
B.PartNumber = "B";
A.Interchanges.Add(new Interchange() { FromPart = A, ToPart = B });
B.Interchanges.Add(new Interchange() { FromPart = B, ToPart = A });
db.Parts.Add(A);
db.Parts.Add(B);
db.SaveChanges();
}
using (var db = new Db())
{
db.Configuration.LazyLoadingEnabled = true;
db.Configuration.ProxyCreationEnabled = true;
var A = db.Parts.Where(p => p.PartNumber == "A").Single();
Console.WriteLine($"Part {A.PartNumber} has {A.Interchanges.Count()} Interchanges");
Console.WriteLine($"Part {A.PartNumber} is interchangable with {A.Interchanges.First().ToPart.PartNumber}");
}
Console.ReadKey();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.