在Entity Framework中存储基于接口的关系

我有我想要实现的这个领域设计理念。 我使用实体框架作为存储机制,我看到这样做的唯一方式似乎并不理想。

我有很多域对象,其中许多需要“可标记”。 用户需要能够以某种方式“标记”它们中的每一个,因为需要注意。

所以我想我会创建这个接口:

public interface IFlaggable
{
    [Required]
    Tally Tally { get; }
    Guid? TallyId { get; }
}

和这些类:

public class Flag
{
    public Guid Id { get; internal set; }
    [Required]
    public Tally Tally { get; internal set; }
    public Guid TallyId { get; internal set; }
    [Required]
    public User Creator { get; internal set; }
    public Guid CreatorId { get; internal set; }
    [Required]
    public FlagIndication Indication { get; internal set; }
}

public class Tally
{
    public Guid Id { get; internal set; }
    public IFlaggable Subject { get; internal set; }
    public ICollection<Flag> Flags { get; internal set; }
}

如果这不明显,FlagIndication是一个枚举。

然后所有其他域对象所要做的就是实现IFlaggable,并且它们成为可标记的。

public class TestFlaggable : IFlaggable
{
    public Guid Id { get; internal set; }
    public Tally Tally { get; internal set; }
    public Guid? TallyId { get; internal set; }
}

看起来很棒。 就数据库而言,它应该工作得很好,因为它是一对一的关系,其他表总是包含一个外键给Tallies表的id字段。

麻烦的是实体框架需要查看界面和扼流圈。 明显。 我们知道实体框架不能很好地与界面配合。

我可以看到使它与Entity Framework一起工作的唯一方法是通过取消界面,创建子类,如从Tally继承的“TestFlaggableTally”,然后每个其他对象都可以拥有它自己的特殊雪花Tally类。

public class Tally
{
    public Guid Id { get; internal set; }
    public ICollection<Flag> Flags { get; internal set; }
}

[Table("TestFlaggableTallies")]
public class TestFlaggableTally : Tally
{
    public TestFlaggable Subject { get; internal set; }
}

public class TestFlaggable
{
    public Guid Id { get; internal set; }
    public TestFlaggableTally Tally { get; internal set; }
    public Guid? TallyId { get; internal set; }
}

这应该工作,但它似乎愚蠢和臃肿。

所以,我在这里问。 有没有更好的办法?

我有一些根本的误解吗?

这是我最好的选择吗?

好吧,打我


我认为EF没有对接口的支持。 - 不正确,请参阅更新

我会建议将你的接口重写成抽象类:

public abstract class FlaggableBase<T>
{
    public abstract T Id { get; internal set; }
    public abstract Tally Tally { get; internal set; }
    public abstract Guid? TallyId { get; internal set; }
}

请注意,我将Id属性添加到基类,以确保从FlaggableBase派生的任何实体都有一个键(EF要求这能够区分实体)。

然后像这样使用它:

public class TestFlaggable : FlaggableBase<Guid>
{
    public override Guid Id { get; internal set; }
    public override Tally Tally { get; internal set; }
    public override Guid? TallyId { get; internal set; }
}

public class Tally
{
    public Guid Id { get; internal set; }
    public FlaggableBase<Guid> Subject { get; internal set; }
    public ICollection<Flag> Flags { get; internal set; }
}

public class Flag
{
    public Guid Id { get; internal set; }
    [Required]
    public Tally Tally { get; internal set; }
    public Guid TallyId { get; internal set; }
    public Guid CreatorId { get; internal set; }
}

使用抽象类而不是接口的唯一缺点是我马上就会看到,您将无法利用延迟加载,因为您无法在覆盖上应用虚拟关键字。

如果出于某种原因,您仍然依赖IFlaggable接口,只需在基类中实现它:

public abstract class FlaggableBase<T> : IFlaggable

UPDATE

我在VS中玩过一段时间,结果你实际上可以用接口来做你想做的事情:

public interface IFlaggable<out T>
{
    T Id { get; }
    Tally Tally { get; }
    Guid? TallyId { get; }
}

然后在你的Tally课堂上:

public class Tally
{
    public Guid Id { get; internal set; }
    public IFlaggable<Guid> Subject { get; internal set; }
    public ICollection<Flag> Flags { get; internal set; }
}

以下是它在数据库中的外观: 在这里输入图像描述

链接地址: http://www.djcxy.com/p/22629.html

上一篇: Storing an interface based relationship in Entity Framework

下一篇: list<T>?