![](/img/trans.png)
[英]Different behavior across domain objects for same properties in Entity Framework Core 2
[英]Entity Framework (Core), multiple refrences to the same table but different objects
我有一个汽车零件:
CREATE TABLE dbo.Part (
Id int IDENTITY(1,1) not null,
PartNumber nvarchar(48) not null,
Colour nvarchar(100) null,
Height int null,
-- etc
)
汽车零件通常是可互换的。 您可以将汽车/卡车上的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)
注意:1个部分可以与许多其他部分互换,在这种情况下,互换是双向的。
现在,假设我有两个部分(零件号A和B),并且它们彼此互换。
当我实例化A部分时,我希望它具有一组Interchanges。 在这种情况下,集合将只有一个对象。 该对象将具有交换注释和零件编号为B的零件对象实例。
同样,如果我编辑零件B,则其集合中将有一个对象,该对象具有互换注释和零件实例,零件编号为A。
有没有一种优雅的方式对此建模?
Google可以为这种模式命名吗?
使用上面的SQL,当我加载部件A时,它具有一个ICollection(使用Entity Framework Power Tools插件创建)。 该交换对象具有交换注释,B部分的实例以及A部分的实例。
在关系模型中,没有一流的方法来为对称关系建模,因此您要么必须在应用程序代码中对其进行处理,要么将其存储为两个单独的行(A,B,“ A和B可互换”)和(B ,A,“ A和B可互换”)
如果为每个关系的倒数添加行,则EF模型很简单,因为零件仅需要一个导航属性。
这是您正在寻找的代码优先模型版本:
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.