.net ORM比较

Tim*_*sen 61 .net comparison orm

我正和某人谈论实体框架,我还没有真正参与其中,但我想学习它.但是,我是否应该学习它仍然有点困惑.我听说很多人说你不应该使用实体框架,但我没有听到任何争论为什么会这样.

所以我的问题是,与其他产品相比,使用实体框架的专业和利益是什么.喜欢

  • NHibernate的
  • DataObjects.Net
  • 等等..

在易用性,可测试性,语义方面......

我知道有一些重复的 问题.但他们都有点过时(2008,2009),说实话,这些论点也缺乏一些东西.我知道实体框架4.0可用,但我还没有找到一个好的(完整的)比较.


答案

这里的一些好人通过解释不同框架的一些细节来回答我的问题.认为将它们展示在这里以供将来参考可能会很好.

Die*_*hon 52

由于J. Tihon在解释EF功能方面表现出色,我只列出了NHibernate在EF周围运行的区域:

  • 高速缓存
    • EF没有任何开箱即用的东西; 只有一个不受支持的样本
    • NH具有完整的缓存支持,包括基于DB的失效.它也是可扩展的和基于提供程序的,这意味着它适用于不同类型的本地和分布式缓存
  • 配料
    • EF没有
    • NH一次性(在任何数据库中)对实体或集合的延迟加载组提供广泛的支持,并以相同的方式持续进行更改(Oracle和SQL Server).还有MultiQueries和Future Queries,允许您在一次往返中任意分组要发送的不同查询.
  • 用户类型
    • EF根本没有可扩展性.它甚至不支持Enum属性
    • NH中没有类型映射是硬编码的.您可以扩展它以支持您可以创建的任何值类型,修改现有类型的映射方式等
  • 收集支持
    • EF仅支持简单的实体集合.多对多总是使用复合键
    • NH支持实体,值类型,组件类型以及索引集合和字典的集合(其中键和值都可以是任何类型).支持具有自己密钥的多对多集合(idbag)
  • 记录
    • EF没有开箱即用.上面列出了相同的不支持的样本
    • NH具有广泛的日志记录功能,可让您轻松调试问题.它默认使用log4net,但您可以使用任何所需的日志记录框架
  • 查询
    • EF将LINQ作为主要查询语言.映射到关系数据库时,LINQ具有高阻抗.EF的提供者不支持使用实体作为参数; 你总是要使用Ids.还有一种记录很差的查询语言
    • NH有LINQ(不像EF那样完整),HQL,QueryOver和Criteria.
  • 事件系统和拦截器
    • EF几乎没有
    • NH有一个强大的事件系统,允许您在会话生命周期的任何一点扩展或替换它的行为:加载对象,持久更改,刷新等.

我认为可扩展性是主要的卖点.NH的每个方面都可以正确地与其他方面分离,使用您可以随时扩展的接口和基本绑定,并在配置选项中公开.

EF遵循默认情况下关闭事件的常用MS模式,我们将在后面看到可扩展的内容.

  • 不要冒犯,但是,只要你是对的,你没有提到NHibernate的缺点.我只是这样说,因为我想学习,根据EF,有什么不足之处吗? (2认同)
  • @oruchreis NHibernate有点难学,并且有一个更有限的LINQ提供者.而已.在其他方面都优于EF. (2认同)

J. *_*hon 34

我花费了大量时间来根据我的需要改变实体框架,因此可以说它满足了ORM所需的大部分要求.但是有些方面太复杂了,因为其他ORM已经表明它可以变得更容易.

例如,开始使用Entity Framework非常简单,因为您可以在Visual Studio中启动Designer并在几分钟内完成一个有效的ORM.但是最终会得到与设计者创建的ObjectContext相关联的Entity-Classes(使用自定义T4模板可以避免这种情况).这不是一件坏事,但它就是那种微软的"入门"方法,你不想在真正的应用程序中使用它.

但是如果您深入了解实体框架,您可以看到,如何避免大部分陷阱:Designer生成EDMX文件,(如果您在XML编辑器中查看)只不过是三者的组合ORM的主要方面,物理存储(您的数据库),概念模​​型(您的实体类)以及它们之间的映射.应用于Visual Studio中的.edmx文件的自定义构建操作会将这3个部分拆分为三个单独的文件,并将它们作为嵌入资源添加到程序集中.在创建ObjectContext时,ConnectionString中使用了这三个文件的路径(这对我来说总是有点混乱).你在这里真正可以做的是自己做这一切.这意味着在XML编辑器(很像NHibernate)中编写存储架构,概念模型和映射,并将它们嵌入到包含模型的程序集中.

基本的Entity Framework基类"ObjectContext"可以从这三个文件构建(它需要MetadataWorkspace和EntityConnection),但重点是,您可以完全控制ObjectContext的创建方式.这为您可能无法从实体框架中获得的许多功能打开了大门.例如:您可以在同一个程序集中嵌入多个SSDL存储架构以匹配特定的数据库类型(我通常为SQL Server添加一个,为SQL Server CE 4.0添加一个).并创建一个构造函数重载,为特定类型的DbConnection选择适当的存储架构.

由于您现在拥有自己的ObjectContext实现,因此可以在其上实现各种接口.就像你自己的IRepository,但因为我喜欢ObjectContext方法,我创建了类似的东西:

interface ICatalog
{
    IEntitySet<Article> { get; }
    void Save();
}

interface IEntitySet<T> : IQueryable<T>
{
    void Add(T);
    void Remove(T); 
}

class EntityFrameworkCatalog : ICatalog
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是如果你有一个Entity Framework ObjectContext,那么创建一个Repository非常简单,而且你可以获得一个IQueryable.根据这些信息,您可以避免在服务和ORM之间建立强大的类耦合,并在测试中完全模拟实体框架.此外,在测试实体框架实现时,您可以在单元测试期间使用SQL Server CE数据库以确保您的映射正常(通常CE的存储架构和完整的SQL Server之间的差异只是一些数据 - 类型).因此,您可以实际测试实体框架实现的所有行为.

这使得Entity Framework很好地适应了现代软件概念,但它并没有对您强制执行此类实践,这使得"入门"变得更加容易.

现在到复杂的位:实体框架有一小组受支持的CLR类型,它们基本上只包括原始类型,如整数,字符串和字节数组.它还提供了一定程度的复杂类型,遵循相同的规则.但是,如果您有一个复杂的实体属性,例如文档的DOM表示,您希望在数据库中将其序列化为XML,那该怎么办呢?据我所知,NHibernate提供了一个名为IUserType的功能,它允许您为您定义这样的映射.在实体框架中,这变得更加复杂,但它仍然以自己的方式存在.概念模型允许您包含程序集内部复杂类型(只要您告诉ObjectContext它(ObjectContext.CreateProxyTypes(Type [])).因此您可以为原始类型创建一个包装器,只有实体框架如下:

 class Document : IXmlSerializable { }
 class Article
 {
     public virtual Document Content { get; set; }
 }
 internal class EntityFrameworkDocument : Document
 {
     public string Xml
     {
         get
         {
              // Use XmlSerializer to generate the XML-string for this instance.
         }
         set
         {
              // Use XmlSerializer to read the XML-string for this instance.
         }
     }
 }
Run Code Online (Sandbox Code Playgroud)

现在EF可以从存储中返回那些序列化文档,将它们写入它,要求您拦截文章的存储并用EntityFrameworkDocument替换一个简单的Document,以确保EF可以序列化它.我相信其他ORM很容易做到这一点而且情况会变得更糟.目前没有办法,使用System.Uri类(它是不可变的,但否则可以工作)或Enum.除了这些限制,您还可以满足大多数需求.但你会花很多时间(就像我一样).

由于我对其他ORM的经验有限,我总结一下:

  • 实体框架在GAC中,即使在客户端配置文件中也是如此
  • 可以自定义实体框架以表示甚至复杂的实体类型(例如,包括一些自引用多对多,或上面的XML序列化)
  • 它可以"抽象"掉,所以你可以坚持使用IRepository等.
  • IQueryable实现(尽管它不像DataObjects.Net那样完整)
  • 它只需要System.Data和System.Data.Entity,你甚至可以为通常需要引用的其他提供者包含多个存储模式,但是如果你坚持使用DbConnection,你可以这样做:

    ICatalog Create(DbConnection connection, string storageSchemaPath) ICatalog CreateMySql(DbConnection mySqlConnection) { return Create(connection, "res://Assembly/Path.To.Embedded.MySql.Storage.ssdl"); }

编辑 我最近发现,如果您的实体和"目录"实现在同一个程序集中,则可以使用内部属性进行XML序列化过程.因此,与其获得的内部EntityFrameworkDocumentDocument您可以添加所谓的内部属性XmlDocument类本身.这仍然只适用于您完全控制您的实体,但它不需要拦截对目录的任何更改,以确保使用您的派生类.CSDL看起来一样,EF只允许映射的属性是内部的.我仍然必须确保这在中等信任环境中有效.

  • 很棒的答案!关于EF4中的枚举,请看这里:http://blogs.msdn.com/b/alexj/archive/2009/06/05/tip-23-how-to-fake-enums-in-ef-4. ASPX.相同的解决方案可用于System.Uri等不可变类型 (3认同)
  • "这就是微软的"入门"方法,你不想在真正的应用程序中使用" - 很棒的声明,不幸的是,它适用于许多其他MS技术. (3认同)

Edu*_*rdo 6

当我们迟早从头开始使用ADO.NET时,我们会感到沮丧并开始寻找其他解决方案.我测试过很多.大多数ORM框架都有很多功能,需要大量的知识.有些看起来很容易(例如:EF,Castle ActiveRecord),但有很多事情你应该关心:

  • 高速缓存
  • 多对多的关系
  • 懒加载
  • 遗产
  • 复合键
  • 如何从调用者封装基础结构
  • 如何生成SQL语句
  • 性能
  • 如何进行高级数据库查询

如果您是一位经验丰富的开发人员,并且您已准备好应对所有这些陷阱和事情,那么我问您:您的同事也是吗?

有更简单的方法来编写ADO.NET,而不是松散地控制正在发生的事情.看看PainlessDAL.

"优雅"编码并不总是最好的方式.