.net ORM比较

我正在和一个关于entity framework的人聊天,我还没有真正意识到,但是我想学习它。 但是,我还是有点困惑,我是否应该学习。 我听到很多人说你不应该使用entity framework,但是我没有听到任何争论。

所以我的问题是, 与其他产品相比 ,使用entity framework的专业人员和使用者是什么? 喜欢

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

在易用性,可testing性,语义…

我知道这里有一些重复的 问题 。 但他们都已经过时了(2008,2009),说实话,论据也是缺乏的。 我知道entity framework4.0是可用的,我还没有find一个很好(完整)的比较呢。


答案

这里的一些好人通过解释关于不同框架的一些细节来回答我的问题。 认为在这里展示以备将来参考可能是件好事。

  • J. Tihon做了一个很好的文章,解释如何在需要更多扩展性时使EF工作。
  • 迭戈Mijelshon已经创造了一个EF的一些陷阱和NHibernate如何解决他们的答案。

由于J. Tihon在解释EF特性方面做了很多工作,所以我将列出NHibernate围绕EF运行圆圈的区域:

  • 高速caching
    • 英孚没有任何东西, 有一个不受支持的示例
    • NH有完整的caching支持,包括基于DB的失效。 它也是可扩展的和基于提供者的,这意味着它适用于不同types的本地和分布式caching
  • 配料
    • EF没有
    • NH同时支持延迟加载实体或集合的组(在任何数据库中),并以相同的方式(Oracle和SQL Server)持久地进行更改。 还有MultiQueries和Future Queries,允许您任意地将不同的查询分组在一个往返中发送。
  • 用户types
    • EF根本没有可扩展性。 它甚至不支持枚举属性
    • 在NH中,没有types映射是硬编码的。 您可以扩展它以支持您可以创build的任何值types,修改现有types映射的方式等
  • 收集支持
    • EF只支持简单的实体集合。 多对多总是使用复合键
    • NH支持实体,值types,组件types以及索引集合和字典(其中键和值都可以是任何types)的集合。 支持多对多的自己的密钥集合(idbag)
  • logging
    • EF没有开箱即用。 上面列出了相同的不受支持的示例
    • NH具有广泛的日志loggingfunction,使您可以轻松debugging问题。 它默认使用log4net,但是你可以使用任何你想要的日志框架
  • 查询
    • EF有LINQ作为主要的查询语言。 当映射到关系数据库时,LINQ具有高阻抗。 EF的提供者不支持使用实体作为参数; 你总是必须使用Id。 还有一个查询语言logging不完善
    • NH有LINQ(不像EF的完整),HQL,QueryOver和Criteria。
  • 事件系统和拦截器
    • EF几乎没有
    • NH有一个function强大的事件系统,可以让你在会话生命周期的任何时候扩展或replace它的行为:加载对象,持久化更改,冲洗等。

我认为可扩展性是主要的卖点。 NH的每个方面都与其他方面正确地分离开来,使用接口和基础类,可以随时扩展,并在configuration选项中公开。

EF遵循通常默认情况下closures的MS模式,稍后我们将看到什么是可扩展的。

我花了大量的时间来实现我的需求,因此可以说它满足了你从ORM中获得的大部分需求。 但是有些方面太复杂了,因为其他的ORM已经表明它可以变得更容易。

例如,开始使用entity framework相当简单,因为您只需在Visual Studio中启动Designer,并在几分钟内就可以运行ORM。 但是最终会得到与devise者创build的ObjectContext绑定的实体类(这可以使用自定义的T4模板来避免)。 这不是一件坏事,但它是微软的“入门”方法,你不想在真正的应用程序中使用。

但是,如果您深入了解entity framework,您可以看到如何避免它的大部分缺陷:devise器生成一个EDMX文件,(如果您在XML编辑器中查看它)只不过是三个ORM的主要方面,物理存储(你的数据库),概念模​​型(你的实体类)以及它们之间的映射。 应用于Visual Studio中的.edmx文件的自定义构build操作将将这3个部分分割为三个单独的文件,并将其作为embedded式资源添加到程序集中。 当创build一个ObjectContext的时候,ConnectionString中使用了这三个文件的path(这对我来说总是让人困惑)。 你可以在这里做的是你自己做的。 这意味着在XML编辑器中编写存储模式,概念模型和映射(就像NHibernate),并将其embedded到包含模型的程序集中。

基本entity framework基类“ObjectContext”可以从这三个文件(它需要一个MetadataWorkspace和EntityConnection)来构build,但重点是,您可以完全控制如何创buildObjectContext。 这为您可能无法从Entity Framework期望的许多function打开了大门。 例如:可以在同一个程序集中embedded多个SSDL存储模式以匹配特定的数据库types(我通常为SQL Server添加一个,SQL Server CE 4.0添加一个)。 并创build一个构造函数重载,为特定types的DbConnectionselect适当的存储模式。

由于您现在拥有自己的ObjectContext实现,所以您可以在其上实现各种接口。 像你自己的IRepository一样,但是因为我喜欢ObjectContext方法,所以我创build了如下的东西:

interface ICatalog { IEntitySet<Article> { get; } void Save(); } interface IEntitySet<T> : IQueryable<T> { void Add(T); void Remove(T); } class EntityFrameworkCatalog : ICatalog { ... } 

但是如果你有一个entity frameworkObjectContext,创build一个Repository非常容易,再加上你得到一个IQueryable。 根据这些信息,您可以避免在服务和ORM之间产生强大的类耦合,并在testing中完整地模拟entity framework。 此外,在testingentity framework实现时,可以在unit testing期间使用SQL Server CE数据库来确保映射是正确的(通常CE和完整的SQL Server的存储模式之间的差异仅仅是一些数据 – types)。 所以你可以实际testing你的entity framework实现的所有行为。

这使得Entity Framework可以很好地与现代的软件概念一起使用,但是它并没有强化你的这种做法,这使得“入门”变得更容易。

现在到复杂的位:entity framework有一小部分受支持的CLRtypes,基本上只包含原始types,如整数,string和字节数组。 它也提供了一些复杂types,遵循相同的规则。 但是如果你有一个复杂的实体属性,比如你想在数据库中序列化为XML的文档的DOM表示。 据我所知,NHibernate提供了一个名为IUserType的function,它允许你为你定义这样的映射。 在entity framework中,这变得复杂得多,但它仍然以自己的方式相当漂亮。 概念模型允许你包含程序集内部的复杂types(只要你告诉ObjectContext它(ObjectContext.CreateProxyTypes(Type []))。所以你可以创build一个你原来的types的包装器,只知道entity framework如下所示:

  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. } } } 

尽pipeEF现在可以从存储中返回这些序列化的文档,但是将它们写入文档需要您拦截文章的存储,并用EntityFrameworkDocumentreplace一个简单的Document,以确保EF能够序列化它。 我确信其他ORM很容易做到,情况变得更糟。 目前没有办法,做同样的System.Uri类(这是不可变的,但否则工作)或一个枚举。 除了这些限制之外,您可以根据您的大部分需求来安装EF。 但是你会花很多时间(就像我做的那样)。

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

  • entity framework位于GAC中,即使在客户端configuration文件中也是如此
  • entity framework可以被定制来表示甚至是复杂的实体types(包括一些自我引用的多对多或者上面的XML序列化)
  • 它可以被“抽象”走,所以你可以坚持IRepository等。
  • IQueryable实现(尽pipe它不像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序列化过程的内部属性。 因此,不要从Document中派生内部EntityFrameworkDocument ,而是可以将名为Xml的内部Property添加到Document类本身。 这仍然只适用于你完全控制你的实体,但它不需要拦截对目录的任何改变,以确保你的派生类被使用。 CSDL看起来是一样的,EF只允许映射的属性是内部的。 我仍然必须确保这可以在中等信任环境下工作。

希望这些将会有所帮助

  • NHibernate与entity framework

  • 打开ORM与entity framework

  • 非常好的比较

当我们迟早使用ADO.NET时,我们感到沮丧,并开始寻找其他解决scheme。 我testing了很多。 这些ORM框架中的大多数都有很多特性,需要大量的知识。 有些看起来非常容易(例如:EF,Castle ActiveRecord),但是您应该关心很多事情:

  • 高速caching
  • 多对多的关系
  • 延迟加载
  • 遗产
  • 复合键
  • 如何封装来自呼叫者的基础设施
  • SQL语句如何生成
  • 性能
  • 如何进行高级数据库查询

如果你是一个有经验的开发人员,而且你已经准备好迎接所有这些陷阱,那么我问你:你的同事也是?

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

“优雅”编码并不总是最好的方式。