C# 在实体框架中存储基于接口的关系
我有这个领域的设计理念,我想实施。我正在使用实体框架作为存储机制,我能看到的唯一方法似乎并不理想 我有很多域对象,其中许多需要“可标记”。用户需要能够以某种方式“标记”每个人需要注意 所以我想我会创建这个界面:C# 在实体框架中存储基于接口的关系,c#,entity-framework,C#,Entity Framework,我有这个领域的设计理念,我想实施。我正在使用实体框架作为存储机制,我能看到的唯一方法似乎并不理想 我有很多域对象,其中许多需要“可标记”。用户需要能够以某种方式“标记”每个人需要注意 所以我想我会创建这个界面: public interface IFlaggable { [Required] Tally Tally { get; } Guid? TallyId { get; } } 这些课程: public class Flag { public Guid Id
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; }
}
看起来很棒。就DB而言,它应该工作得很好,因为它是一对一的关系,而其他表总是包含一个指向计数表id字段的外键
问题在于实体框架查看了接口并阻塞了它。明显地我们知道实体框架不能很好地处理接口
我能看到的使其与实体框架一起工作的唯一方法是取消接口,创建从Tally继承的子类,如“TestFlaggablely”,然后每个其他对象都可以拥有自己的特殊snowflake 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; }
}
公共类计数
{
公共Guid Id{get;内部集合;}
公共ICollection标志{get;internal set;}
}
[表(“TestFlaggableTables”)]
公共类TestFlaggablely:Tally
{
公共TestFlaggable主题{get;internal set;}
}
公共类TestFlaggable
{
公共Guid Id{get;内部集合;}
公共TestFlaggableTally{get;internal set;}
公共Guid?TallyId{get;内部集合;}
}
这应该行得通,但它看起来既愚蠢又臃肿
所以,我是来问你的。有更好的办法吗
我有一些基本的误解吗
这是我最好的选择吗
好的,点击我吧我认为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; }
}
公共抽象类FlaggableBase
{
公共抽象T Id{get;内部集合;}
公共抽象计数{get;内部集合;}
公共抽象Guid?TallyId{get;内部集合;}
}
请注意,我在基类中添加了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; }
}
公共类TestFlaggable:FlaggableBase
{
公共重写Guid Id{get;internal set;}
公共覆盖计数{get;内部集;}
公共覆盖Guid?TallyId{get;内部集合;}
}
公务舱理货
{
公共Guid Id{get;内部集合;}
公共FlaggableBase主题{get;internal set;}
公共ICollection标志{get;internal set;}
}
公共班级旗帜
{
公共Guid Id{get;内部集合;}
[必需]
公共计数{get;内部集合;}
公共Guid TallyId{get;内部集合;}
公共Guid创建者ID{get;内部集合;}
}
使用抽象类而不是我马上看到的接口的唯一缺点是,您将无法利用延迟加载,因为您无法在覆盖上应用virtual关键字
如果出于某种原因,您仍然依赖IFlaggable接口,只需在基类中实现它:
public abstract class FlaggableBase<T> : IFlaggable
public抽象类FlaggableBase:IFlaggable
更新
我在VS中玩了一点,结果证明,您可以使用接口实现您想要的功能:
public interface IFlaggable<out T>
{
T Id { get; }
Tally Tally { get; }
Guid? TallyId { get; }
}
公共接口IFlaggable
{
T Id{get;}
计数{get;}
Guid?TallyId{get;}
}
然后在理货课上:
public class Tally
{
public Guid Id { get; internal set; }
public IFlaggable<Guid> Subject { get; internal set; }
public ICollection<Flag> Flags { get; internal set; }
}
公共类计数
{
公共Guid Id{get;内部集合;}
公共iFlagable主题{get;内部集;}
公共ICollection标志{get;internal set;}
}
以下是它在数据库中的外观:
你说EF窒息是什么意思?我已经在我的实体上使用了很多次接口。只是它不能用这样的属性创建关系。我明白为什么。实体框架无法理解“public IFlaggable Subject{get;internal set;}”属性。哦,我明白了。我没有具体做过这件事。不过,这让我很感兴趣。我真诚地希望你找到一个更好的方法。这在集合中似乎不起作用:当我使用EF检索Tall实例时,接口实体集合(此处为IFlaggables)从未填充过。一旦你将你的财产虚拟化,它将被填充。
public class Tally
{
public Guid Id { get; internal set; }
public IFlaggable<Guid> Subject { get; internal set; }
public ICollection<Flag> Flags { get; internal set; }
}