我在Entity Framework中有一个Foo
实体。但我将它从IFoo
继承,以便我的业务逻辑只知道IFoo
- 从而抽象出实体框架。
问题是Foo
有Bar
个实体的集合。此集合的类型为EntityCollection<Bar>
。
如果我将此集合原样放在IFoo
中,我会使IFoo
依赖于实体框架。所以我想把它作为ICollection<IBar>
,但这不能编译(自然)。
我能想到的唯一解决方案是转到Entity Framework设计器生成的具体Foo
实现,并将集合从EntityCollection<Bar>
更改为ICollection<IBar>
。但我担心这会对“幕后”的实体框架产生影响。
我是否有办法独立于实体框架定义IFoo
和IBar
,同时仍然将Foo
和Bar
作为实施它们的EF实体进行维护? IFoo
和IBar
是否有意义,如果我无法实现我的目标那么独立?
答案 0 :(得分:8)
您所指的一般概念是“持久性无知”(PI),尽管这通常直接应用于实体本身而不是消耗实体的代码。
无论如何,Hibernate和NHibernate原生支持PI,但微软实体框架的初始版本却没有。 MS为此抓住了很多优势,PI可能是下一个版本中讨论最多的第一个功能(无论何时都是这样)。
至于你试图用接口做什么,在检索后需要修改Bars的集合吗?如果答案是肯定的,那就没有简单的答案。甚至协方差也无法帮助你,因为ICollection<T>
有一个Add方法。
如果集合是只读的,那么您可以考虑将其公开为IEnumerable<IBar>
。 Enumerable.Cast
方法使这非常方便。
interface IFoo
{
IEnumerable<IBar> Bars { get; }
}
partial class Foo : IFoo
{
IEnumerable<IBar> IFoo.Bars
{
get { return Bars.Cast<IBar>(); }
}
}
另外,我知道at least one effort使当前版本的EF支持持久性无知。
答案 1 :(得分:2)
我是Java开发人员,所以我不能对Entity Framework的任何权限发表评论。我可以告诉你,像Hibernate这样的ORM解决方案可以让POJO持久化,而不必求助于通用的抽象类,接口或修改字节代码。它处理的关系就像1:m你引用你的Foo和Bar而不必使用特殊的集合类。
特殊的酱被外化到映射配置和Hibernate本身。
我读到的关于实体框架的一点点表明它是一个具有相同目标的ORM解决方案:POCO持久性。我没有看到任何接口提及。我不能从你的例子中看出它们的必要性,因为它太抽象了。
我推断,有可能在业务对象和持久层之间获得独立性,而不必求助于这些接口,因为我知道Hibernate会这样做。我会说Spring的JDBC解决方案也可以实现它,因为不需要通用接口。他们使用RowMapper构造将数据从查询中传送到对象中。
我希望我可以准确地告诉你如何使用Entity Framework,但也许你会知道它可以做到。
答案 2 :(得分:2)
使用分部类从自动生成的EF对象中分离逻辑和规则。在下面的示例中,使用partial关键字将FooEntityObject类拆分为两个。我之前使用过EF和LINQ to SQL这种技术。部分类可以存储在单独的文件中,因此如果再次重新生成EF对象,则自定义代码不会被覆盖。
interface IFoo
{
public ICollection<IBar> GetBars();
}
public partial class FooEntityObject : IFoo
{
public ICollection<IBar> GetBars()
{
// convert EntityCollection<Bar> into ICollection<IBar> here
}
}
public partial class FooEntityObject
{
EntityCollection<Bar> Bars{get;set;}
}
答案 3 :(得分:2)
我最近写了一篇关于此事的综合文章:Persistence Ignorance in ADO.NET Entity Framework。您可能想看看EFPocoAdapter。这样做,它最终将弃用到EF v2。
对于它的价值,我使用的是EFPocoAdapater,它一直很适合我。
答案 4 :(得分:2)
我们一直在为LINQ to SQL做同样的事情。我通过编写一个包含IList
的类并根据需要强制转换为正确类型来解决集合问题。看起来有点像这样:
public class ListWrapper<TSource, TTarget> : IList<TTarget>
where TTarget : class
where TSource : class, TTarget
{
private IList<TSource> internalList;
public ListWrapper(IList<TSource> internalList)
{
this.internalList = internalList;
}
public void Add(TTarget item)
{
internalList.Add((TSource)item);
}
public IEnumerator<TTarget> GetEnumerator()
{
return new EnumeratorWrapper<TSource, TTarget>(internalList.GetEnumerator());
}
// and all the other IList members
}
EnumeratorWrapper类似地包装IEnumerator并执行转换。 在LINQ to SQL部分类中,我们公开了如下属性:
public IList<ICustomer> Foos
{
get
{
return new ListWrapper<Foo, IFoo>(this.Foos_internal);
}
}
对公开列表的任何更改都将在内部EntitySet上执行,以便它们保持同步。
这种方法运作得很好,但我的感觉是整个方法比它的价值更麻烦,我是一个巨大的NHibernate粉丝,并坚信P.I.但是我们已经做了很多额外的努力,并没有真正看到任何优势。我们使用存储库模式抽象出实际的DataContext访问,我认为这是将自己从LINQ转换为SQL的关键部分。