我正在重构其他人的代码,涉及ef6,code-firt。我正在尝试重复使用数据库列,以便它们参与多个外国密钥关系。
我知道,这样做是在使我的架构不正当,但是这样做,这将使我能够在原始设计中缺少的模型之间建立更直接的关系。我希望这种情况发生在最小的基础数据库模式,因为有手写的sprocs和udf会受到影响。
下面的模型代表当前状态:
Frame
由FrameType
和Moulding
组成。帧是唯一的,因为没有重复FrameType
或Moulding
,因此我们在FrameType_Id
和Moulding_Id
上有一个复合主键。
public class Frame
{
[Key,Column(Order = 0)]
[ForeignKey("Moulding")]
public int Moulding_Id { get; set; }
public Moulding Moulding { get; set; }
[Key, Column(Order = 1)]
[ForeignKey("FrameType")]
public int FrameType_Id { get; set; }
public FrameType FrameType { get; set; }
}
我们可以假设FrameType
和Moulding
public class FrameType
{
public int Id{get; set;}
public ICollection<Frame> Frames{get; set;}
}
public class Moulding
{
public int Id{get; set;}
public ICollection<Frame> Frames{get; set;}
}
在其他地方,我们有一个Product
,它同时引用FrameType
和Moulding
:
public class Product
{
public int Id{get; set;}
[ForeignKey("Moulding")]
public int Moulding_Id { get; set; }
public Moulding Moulding { get; set; }
[ForeignKey("FrameType")]
public int FrameType_Id { get; set; }
public FrameType FrameType { get; set; }
}
但是,至关重要的是,不直接引用Frame
。
我想将属性添加到Frame
:
public ICollection<Product> Products{get; set;}
和Product
:
public Frame Frame{get; set;}
重新使用Moulding_Id
和FrameType_Id
字段不仅是Moulding
和FrameType
的外国密钥,还可以直接作为Frame
的复合外键。
在EF中,这种"重复使用"是否可能?
是的,这是可能的。唯一的EF6要求是(1(引用的实体属性为PK,(2(在重复使用FK的各个部分的情况下,FK属性是明确定义的,因为没有将2个阴影属性映射到一个和同名的方法。幸运的是,您的样本模型满足了这两个条件。
我个人更喜欢流利的配置,因为它更明确,IMO更容易遵循。或者,如果您更喜欢数据注释,请用ForeignKey
属性而不是倒数对导航属性进行装饰通过数据账单。
将其应用于您的示例模型如下:
public class Frame
{
[Key, Column(Order = 0)]
public int Moulding_Id { get; set; }
[Key, Column(Order = 1)]
public int FrameType_Id { get; set; }
[ForeignKey("Moulding_Id")]
public Moulding Moulding { get; set; }
[ForeignKey("FrameType_Id")]
public FrameType FrameType { get; set; }
public ICollection<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public int Moulding_Id { get; set; }
public int FrameType_Id { get; set; }
[ForeignKey("Moulding_Id")]
public Moulding Moulding { get; set; }
[ForeignKey("FrameType_Id")]
public FrameType FrameType { get; set; }
[ForeignKey("Moulding_Id,FrameType_Id")]
public Frame Frame { get; set; }
}
但是,有一个小问题 - 以上引入了多个级联路径,通常需要您关闭级联删除。反过来,哪些将需要流利的配置,一旦您使用流利的配置,就不需要ForeignKey
数据注释,因此请将其从Product.Frame
属性中删除并使用以下内容:
modelBuilder.Entity<Product>()
.HasRequired(e => e.Frame)
.WithMany(e => e.Products)
.HasForeignKey(e => new { e.Moulding_Id, e.FrameType_Id })
.WillCascadeOnDelete(false);