我有这个想要实现的域设计理念.我正在使用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; } }
以下是它在数据库中的外观: