实体框架:重用外键

时间:2017-05-02 22:52:31

标签: c# sql-server entity-framework entity-framework-6 foreign-keys

我正在重构其他涉及EF6的代码,代码优先。我正在尝试重用数据库列,以便它们涉及多个外键关系。

我知道通过这样做,我正在对我的模式进行非规范化,但这样做,它将允许我在原始设计中缺少的模型之间建立更直接的关系。我希望这可以通过对底层数据库模式的最小更改来实现,因为有手写的sprocs和UDF会受到影响。

以下模型代表了当前的事态:

FrameFrameTypeMoulding组成。框架是唯一的,因为没有重复FrameTypeMoulding对,因此我们在FrameType_IdMoulding_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; }
}

我们可以假设FrameTypeMoulding

的最小实现
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,它引用了FrameTypeMoulding

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_IdFrameType_Id字段不仅可以作为MouldingFrameType的外键,还可以直接作为Frame的复合外键使用

EF中是否可以“重复使用”外键?

1 个答案:

答案 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);