2011-02-24 50 views
60

我正在和某人討論實體框架,但我還沒有真正意識到它,但我想了解它。但是,我仍然有點困惑,我是否應該學習它。我聽到很多人說你不應該使用實體框架,但是我沒有聽到任何爭論。.net ORM比較

所以我的問題是,什麼是使用實體框架compared to other products的親和騙局。像

  • NHibernate的
  • DataObjects.Net
  • 等。

在易用性,可測性,語義方面...

我知道有一些duplicatequestions對這個。但他們都已經過時了(2008,2009),說實話,論據也缺乏一些東西。我知道實體框架4.0是可用的,我還沒有找到一個很好的(完整的)比較。


答案

這裏的某些漂亮的人都通過解釋在不同的框架的一些細節回答我的問題。認爲在這裏展示以備將來參考可能是件好事。

+0

可能重複(http://stackoverflow.com/questions/1377236/nhibernate-entity-framework-active-records-or-linq2sql) – 2011-02-24 16:22:13

+6

除了之一是從09年9月份開始,EF – 2011-02-24 17:21:51

+2

的變化很大我對這個問題的回答在2010年6月更新,從那時起EF4或其他ORM沒有多大變化。無論如何,你不應該因爲想要更新鮮的答案而造成重複的問題。 – 2011-02-25 11:47:17

回答

32

我花了大量時間來彎曲實體框架,以我的需求,因此可以說,它符合大多數你從一個ORM想要的要求。但有些方面太複雜了,因爲其他ORM已經表明它可以變得更容易。

例如,開始使用Entity Framework相當容易,因爲您可以在Visual Studio中啓動Designer並在幾分鐘內啓動一個可用的ORM。但是最終會得到與設計者創建的ObjectContext綁定的實體類(這可以使用自定義的T4模板來避免)。這不是一件壞事,但它就是那種微軟的「入門」方法,你不想在真正的應用程序中使用。

但是,如果您深入瞭解實體框架,您可以看到如何避免大部分缺陷:設計器生成一個EDMX文件,該文件(如果您在XML編輯器中查看)只不過是一個ORM的三個主要方面,物理存儲(您的數據庫),概念模​​型(您的實體類)以及它們之間的映射的組合。在Visual Studio中應用於.edmx文件的自定義構建操作會將這3個部分分割爲三個單獨的文件,並將它們作爲嵌入式資源添加到程序集中。當創建一個ObjectContext時,ConnectionString中使用這三個文件的路徑(這對我來說總是有點混亂)。你可以在這裏做的是你自己做的。這意味着在XML編輯器中編寫存儲模式,概念模型和映射(很像NHibernate),並將其嵌入到包含模型的程序集中。

基本實體框架基類「ObjectContext」可以從這三個文件構建(它需要MetadataWorkspace和EntityConnection),但重點是,您可以完全控制如何創建ObjectContext。這爲您可能無法從Entity Framework期望的許多功能打開了大門。例如:可以在同一個程序集中嵌入多個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 
{ 
    ... 
} 

但創建一個存儲庫,如果你有一個實體框架ObjectContext的是很容易,再加上你得到一個IQueryable。基於這些信息,您可以避免在服務和ORM之間產生強大的類耦合,並在測試中完整地剔除實體框架。此外,在測試實體框架實施時,您可以在單元測試期間使用SQL Server CE數據庫,以確保映射無誤(通常,CE和完整SQL Server的存儲模式之間的差異僅僅是一些數據 - 類型)。所以你可以實際測試你的實體框架實現的所有行爲。

這使得Entity Framework可以很好地與現代的軟件概念一起使用,但它不會對您實施這樣的實踐,這使得「入門」變得更加簡單。

現在到了複雜的位:實體框架有一小組受支持的CLR類型,基本上只包括原始類型,如int,字符串和字節數組。它還提供了一些複雜類型,遵循相同的規則。但是,如果你有一個複雜的實體屬性,比如文檔的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. 
     } 
    } 
} 

Altough的EF現在可以從存儲返回的序列化文件,將它們寫入它,需要你攔截物品的存儲和與EntityFrameworkDocument更換一個簡單的文檔,以確保EF可以序列化它我確信其他ORMs很容易做到這一點,它變得更糟,目前沒有辦法,做System.Uri類(這是不可改變的,但否則工作)或一個Enum除了這些限制之外,您還可以根據您的大部分需求來配置EF生病花費了很多時間(就像我做的那樣)。

因爲我與其他的ORM的經驗是有限的,我會總結:

  • 實體框架是在GAC中,即使在客戶端配置文件
  • 實體框架可以定製,以代表甚至複雜的實體類型(包括一些自引用許多一對多例如,或者上面的XML序列化)
  • 它可以是「抽象」的,所以你能堅持到IRepository等
  • IQueryable的執行(altough它不是完整的作爲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的內部屬性添加到Document類本身。這仍然只適用於完全控制實體的情況,但它不需要攔截對目錄的任何更改,以確保使用派生類。 CSDL看起來一樣,EF只允許映射的屬性是內部的。我仍然必須確保這可以在中等信任環境下工作。

+3

很好的回答!關於EF4中的枚舉,請看這裏:http://blogs.msdn.com/b/alexj/archive/2009/06/05/tip-23-how-to-fake-enums-in-ef-4。 ASPX。同樣的解決方案可以用於像System.Uri – 2011-02-24 09:14:48

+0

這樣的不可變類型。這會起作用,但它需要修改實體類以適應ORM的需求。我通常試圖避免的東西。但它肯定比一個普通的int更接近枚舉。 – 2011-02-24 09:25:31

+0

當然,我同意,如果不需要,情況會好一些。但它是一個解決方案,將對象留在有用的設計中 – 2011-02-24 10:13:09

51

由於J.吉洪做了解釋EF功能非常出色,我只是列表,NHibernate的運行周圍EF圈區域:

  • 緩存
    • EF無關開箱;只有一個unsupported sample
    • NH有完整的緩存支持,包括基於DB的無效。這也是可擴展的,基於提供者的,這意味着它可以與不同類型的本地和分佈式緩存
  • 配料
    • EF現在沒有
    • NH對實體或者集合的延遲加載團體的廣泛支持(在任何數據庫中),並以相同的方式持續進行更改(Oracle和SQL Server)。還有MultiQueries和Future Queries,允許您隨意將不同的查詢分組在一個往返中發送。
  • 用戶類型
    • EF沒有可擴展性可言。它甚至不支持枚舉屬性
    • 沒有類型映射在NH中硬編碼。你可以擴展它來支持,你可以創造任何價值類型,修改現有的類型映射方式等
  • 收集支持
    • EF僅支持實體的簡單集合。多對多始終使用組合鍵
    • NH支持實體,值類型,組件類型以及索引集合和字典(其中鍵和值都可以是任何類型)的集合。用自己的鑰匙許多一對多的集合支持(idbag)
  • 記錄
    • EF沒有記錄開箱。有上面列出的相同不受支持的示例
    • NH具有廣泛的日誌記錄功能,可讓您輕鬆調試問題。它使用log4net的默認,但你可以使用任何日誌框架你想
  • 查詢
    • EF具有LINQ作爲主要的查詢語言。映射到關係數據庫時,LINQ具有高阻抗。 EF的提供者不支持使用實體作爲參數;你總是必須使用Id。還有一種查詢語言記錄不完整
    • NH有LINQ(不像EF完整),HQL,QueryOver和Criteria。
  • 事件系統和攔截
    • EF幾乎沒有什麼
    • NH具有強大的事件系統,使您可以擴展或在會話生命週期的任何點替換它的行爲:加載的對象,堅持變化,潮紅等

我覺得擴展性是其主要賣點。 NH的每個方面都與其他方面正確分離,使用接口和基礎分類,您可以隨時擴展,並在配置選項中公開。

EF遵循默認情況下關閉事物的常規MS模式,稍後我們將看到什麼是可擴展的。

+0

我只是補充一點,EF有一些事件 - 一個是當你實現一個對象時,另一個是保存更改之前。 – 2011-04-01 13:44:45

+1

@JeanHominal:你說得對。他們不是很好用,雖然... – 2011-04-01 14:01:52

+2

不要冒犯但是,只要你是對的,你沒有提到NHibernate的缺點。我只是這樣說,因爲我想學習,根據EF的說法,有什麼不足嗎? – oruchreis 2012-03-31 01:15:12

6

當我們遲早地從頭開始使用ADO.NET時,我們感到沮喪並開始尋找其他解決方案。 我測試了很多。這些ORM框架中的大多數都有很多特性,需要大量的知識。有些人似乎在一開始很容易(如:EF,城堡的ActiveRecord),但也有你們關心的事情太多了:

  • 緩存
  • 許多一對多的關係
  • 延遲加載
  • 繼承
  • 組合鍵
  • 如何封裝從呼叫者infratructure
  • 如何SQL語句生成
  • 性能
  • 如何讓先進的數據庫查詢

如果你是一個有經驗的開發人員,你準備好了所有的陷阱和東西那我問你:是你的同事也?

有更簡單的方法來編寫ADO.NET,而不是鬆散控制發生的事情。看看PainlessDAL

「優雅」編碼並不總是最好的方法。

[NHibernate的,實體框架,活動記錄或LINQ2SQL]的