各種ORM框架對比
目前框架有以下
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 = null,bool 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年未更新代碼,里面類文件比較多,算不上輕量級,運用上比較簡單
以下是代碼截圖
![]()
Chain
一種基於函數式編程理念的Fluent ORM,項目今年少有更新,運用上幾乎不寫腳本,類似EF的數據對應模型開發,和我們常規面向對象開發有點差異,我對它的獲知來源也是在InfoQ上得知,
//插入數據 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(); }
壓測截圖

這個壓測圖是截圖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,會考慮后期的讀寫庫分離並且分布式措施,內部集成短期數據緩存機制等功能。


