各種ORM框架對比(理論篇,歡迎來觀摩,並且糾正部分錯誤,防止誤區)


各種ORM框架對比

目前框架有以下

  1. PetaPoco
  2. Dapper.NET
  3. Massive
  4. Simple.Data
  5. Chain

PetaPoco

輕量級,以前單文件,目前有維護形成項目級別,適合多個數據庫,開發入手比較快,二次開發擴展簡單,模型Emit映射,數據交互需要Code,並且需要編寫腳本,接口上有自動翻頁,支持多對象查詢返回

使用示例:

//保存對象
db.Save(article);
db.Save(new Article { Title = "Super easy to use PetaPoco" });
db.Save("Articles", "Id", { Title = "Super easy to use PetaPoco", Id = Guid.New() });

//獲取一個對象
var article = db.Single<Article>(123);
var article = db.Single<Article>("WHERE ArticleKey = @0", "ART-123");

//刪除一個對象
db.Delete(article);
db.Delete<Article>(123);
db.Delete("Articles", "Id", 123);
db.Delete("Articles", "ArticleKey", "ART-123");

 


Dapper.NET

輕量級,單文件,支持多數據庫,模型Emit反射,數據交互需要Code,開發入手也比較快,二次開發擴展簡單,支持多對象查詢返回,優勢在於寫入數據比PetaPoco更加靈活,但編碼性工作要求會更多

使用示例:

注意:所有擴展方法假定連接已打開,如果連接關閉,它們將失敗

//IDbConnection擴展查詢
public  static  IEnumerable < T > Query < T >(this IDbConnection conn,string  sql,object  param  =  null,SqlTransaction  transaction  =  nullbool  buffered  =  true

 

  • 單個查詢:
public class Dog
{
    public int? Age { get; set; }
    public Guid Id { get; set; }
    public string Name { get; set; }
    public float? Weight { get; set; }

    public int IgnoredProperty { get { return 1; } }
}            
//簡單查詢
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });
//驗證統計數量
dog.Count()
    .IsEqualTo(1);
//驗證屬性是否為null
dog.First().Age
    .IsNull();
//驗證屬性是否匹配
dog.First().Id
    .IsEqualTo(guid);

 

  • 多個查詢,並且返回一個動態列表:
 
        
 
         
//查詢兩行數據
var rows = connection.Query("select 1 A, 2 B union all select 3, 4");
//行一數據
((int)rows[0].A)
   .IsEqualTo(1);
((int)rows[0].B)
   .IsEqualTo(2);
//行二數據
((int)rows[1].A)
   .IsEqualTo(3);
((int)rows[1].B)
    .IsEqualTo(4);
 
  • IDbConnection擴展執行
public static int Execute(this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null)

 

  • 執行一個插入操作
connection.Execute(@"
  set nocount on 
  create table #t(i int) 
  set nocount off 
  insert #t 
  select @a a union all select @b 
  set nocount on 
  drop table #t", new {a=1, b=2 })
   .IsEqualTo(2);

 

  • 同一張表插入多個數據

注意:如果是大批量插入不建議這么使用,請用ADO.NET自帶的BatchInsert

connection.Execute(@"insert MyTable(colA, colB) values (@a, @b)",
    new[] { new { a=1, b=1 }, new { a=2, b=2 }, new { a=3, b=3 } }
  ).IsEqualTo(3);

 


Massive

非單文件,但也是輕量級,項目在持續維護,支持多數據庫,和dapper和PetaPoco運用有點截然不同;它是用類對象繼承DynamicModel來模擬實體對象的查詢和寫入,似乎沒有看到多對象多表聯合查詢和返回,局限性還是比較小

代碼示例

public class Products:DynamicModel {
    public Products():base("northwind", "products","productid") {}
}
var table = new Products();
var products = table.All();
//獲取查詢字段和搜索條件
var productsFour = table.All(columns: "ProductName as Name", where: "WHERE categoryID=@0",args: 4);
//分頁查詢
var result = tbl.Paged(where: "UnitPrice > 20", currentPage:2, pageSize: 20);
var poopy = new {ProductName = "Chicken Fingers"};
//更新 Product對象到表, 條件 ProductID = 12 ,設置 ProductName of "Chicken Fingers"
table.Update(poopy, 12)

//插入數據
var table = new Categories();
var inserted = table.Insert(new {CategoryName = "Buck Fify Stuff", Description = "Things I like"});
//插入成功后得到返回新對象
var newID = inserted.CategoryID;

 


Simple.Data

  • ADO-based access to relational databases, with providers for:
    • SQL Server 2005 and later (including SQL Azure)
    • SQL Server Compact Edition 4.0
    • Oracle
    • MySQL 4.0 and later
    • SQLite
    • PostgreSQL
    • SQLAnywhere
    • Informix
  • MongoDB
  • OData

項目已經比較老,目前已經4-5年未更新代碼,里面類文件比較多,算不上輕量級,運用上比較簡單

以下是代碼截圖

 imageimage 

image


Chain

一種基於函數式編程理念的Fluent ORM,項目今年少有更新,運用上幾乎不寫腳本,類似EF的數據對應模型開發,和我們常規面向對象開發有點差異,我對它的獲知來源也是在InfoQ上得知,

地址:http://www.infoq.com/cn/articles/repository-implementation-strategies?utm_source=articles_about_dotnet&utm_medium=link&utm_campaign=dotnet

//插入數據
public int Insert(Employee employee)
{
    return m_DataSource.Insert("HR.Employee", employee).ToInt32().Execute();
}

//更新數據
public void Update(Employee employee)
{
    m_DataSource.Update("HR.Employee", employee).Execute();
}

//初學者更新實體(但容易出問題,如果對應的漏寫了一個屬性的賦值)
public void Update(Employee employee)
{
    using (var context = new CodeFirstModels())
    {
        var entity = context.Employees.Where(e => e.EmployeeKey == employee.EmployeeKey).First();
        entity.CellPhone = employee.CellPhone;
        entity.FirstName = employee.FirstName;
        entity.LastName = employee.LastName;
        entity.ManagerKey = employee.ManagerKey;
        entity.MiddleName = employee.MiddleName;
        entity.OfficePhone = employee.OfficePhone;
        entity.Title = employee.Title;
        context.SaveChanges();
    }
}

//中級者更新
public void Update(Employee employee)
{
    using (var context = new CodeFirstModels())
    {
        context.Entry(employee).State = EntityState.Modified;
        context.SaveChanges();
    }
}

//獲取指定表全部數據
public IList<Employee> GetAll()
{
    return m_DataSource.From("HR.Employee").ToCollection<Employee>().Execute();
}

 


壓測截圖

image

這個壓測圖是截圖Dapper官方代碼庫里的,估計有點老,下面評論的朋友也糾正了這點,謝謝,所有先忽略這個EF的壓測參考,等我實際壓測后,會具體分享出優缺點

在博客園里發現這篇軟文對EF VS Dapper 的測試:http://www.cnblogs.com/so9527/p/5674498.html#!comments ,那其實我也不用測試壓力差距,唯一告訴我們EF也有自身的優勢,微軟這個產品迭代這么久的版本肯定一直在提升自己,如果有興趣可以關注 Core 版本的性能,據說很快;如果熟悉DDD構架模式也知道利用EF這兩者也是相當的默契度

 

由於網友:我是so 的要求,我也簡單測試一下他的產品,代碼如下,就只考慮單線程

 

       

Console.WriteLine($"開始Chloe測試");
using (MsSqlContext msSqlContext = new MsSqlContext("server=(local);user id=test;password=test;database=TestDb;"))
{
IQuery<Order> query = msSqlContext.Query<Order>();
//預熱,因為我沒去查閱你的源碼,默認考慮預熱
query.FirstOrDefault();
Stopwatch stopwatch = Stopwatch.StartNew();
IList<long> tmsList = new List<long>();
for (int i = 0; i < 10; i++)
{
stopwatch.Restart();
var data = query.ToList();
stopwatch.Stop();
var tms = stopwatch.ElapsedMilliseconds;
tmsList.Add(tms);
Console.WriteLine($"耗時:{tms}");
}
Console.WriteLine($"平均:{tmsList.Average()}");
Console.ReadKey();
}

 
         


Console.WriteLine($"開始Dapper測試");
using (IDbConnection connection = new SqlConnection("server=(local);user id=test;password=test;database=TestDb;"))
{
//也進行預熱
connection.QueryFirst("SELECT TOP 1 OrderId,OrderNo FROM [Order]");
Stopwatch stopwatch = Stopwatch.StartNew();
IList<long> tmsList = new List<long>();
for (int i = 0; i < 10; i++)
{
stopwatch.Restart();
var data = connection.Query<Order>("SELECT OrderId,OrderNo FROM [Order]"); ;
stopwatch.Stop();
var tms = stopwatch.ElapsedMilliseconds;
tmsList.Add(tms);
Console.WriteLine($"耗時:{tms}");
}
Console.WriteLine($"平均:{tmsList.Average()}");
Console.ReadKey();
}

 
        

 

100萬數據讀取,模型包含兩個字段,在DEBUG模式下單線程測試,單位:毫秒,由於每個人機器配置不同僅供參考

測試最終結果:

 


最后分析對比表,如果有異議,歡迎糾正

ORM框架 難易度 開源 輕量級度 性能 擴展性 項目切入
PetaPoco 容易 方便 麻煩點(非T4)
Dapper 容易 方便 麻煩點
Massive 還行 有點繁瑣
Simple.Data 容易 足夠用 快速
Chain 容易 還可以 足夠用 快速
EF 容易 還可以 足夠用 快速

 糾正一下表格,把編碼級改成項目切入更合適....

這篇對比文章的產生主要是我們公司的開發框架體系在做調整,需要基礎框架來逐步切入到各個項目中,順便也調研了這些輕量級ORM,到時進行權衡對比后再此基礎上二次可能開發一個自己ORM,會考慮后期的讀寫庫分離並且分布式措施,內部集成短期數據緩存機制等功能。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM