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

我有这个想要实现的域设计理念.我正在使用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; }
}

看起来很棒.就DB而言,它应该工作得很好,因为它是一对一的关系,而其他表总是包含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; }
}

以下是它在数据库中的外观:

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...