我正在重构其他涉及EF6的代码,代码优先。我正在尝试重用数据库列,以便它们涉及多个外键关系。
我知道通过这样做,我正在对我的模式进行非规范化,但这样做,它将允许我在原始设计中缺少的模型之间建立更直接的关系。我希望这可以通过对底层数据库模式的最小更改来实现,因为有手写的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中是否可以“重复使用”外键?
答案 0 :(得分:2)
是的,这是可能的。唯一的EF6要求是(1)引用的实体属性是PK,(2)在重用FK的部分的情况下,FK属性被显式定义,因为没有将2个阴影属性映射到同一个名称的方法。幸运的是,您的样本模型满足两个条件。
我个人更喜欢流畅的配置,因为它更明确,IMO更容易理解。或者,如果您更喜欢数据注释,请使用ForeignKey
属性而不是逆向装饰导航属性,因为虽然bot允许映射单个FK字段,但前者是唯一的映射方式复合FK字段通过数据通知。
将它应用于您的样本模型如下所示:
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);