DNetORM 是一款基於.net的輕量級的、輕配置的ORM框架,核心代碼只有100K大小,支持SQLSERVER、MYSQL、ORACLE、SQLite數據庫,DNetORM的核心思想是,將最接近原生的C#代碼映射出最符合場景的sql語句,從而最大程度提升開發效率。
DNetORM使用起來非常簡單,無需依賴配置文件,DNetORM拒絕封裝過多的方法,這會造成使用的難度,只是封裝了增刪改查基本常用的一些方法,所以使用起來會非常簡單。
DNetORM對於多表的聯查進行了常規的封裝支持了LEFT JOIN, INNER JOIN ,GROUP BY , ORDER BY, WHERE,對於復雜的寫法,建議使用DNetORM提供的SQL查詢接口,我們在開發中使用orm是為了提升開發效率,節省開發時間,這是為什么使用orm的目的,orm不是為了避免使用sql,實際開發中有很多查詢語句會很復雜,如果依賴orm,首先orm即使支持的話也會寫的很復雜,並不直觀,以往有開發的筒子們在用linq實現相同的復雜一點的sql的時候,寫個sql也就是5分鍾,但是為了實現linq的寫法寫了半小時,還寫的不正確,所以這些都是違背開發精神的。所以ORM是一個開發工具,它的出現就是為了節省開發時間、提升開發效率,使用orm可以幫你解決增刪改的繁雜瑣事,在查詢上,orm幫你處理了大部分的單表查詢,在多表的查詢上,orm幫你處理簡單的多表查詢,幫你最快的獲取數據,至於復雜的sql查詢,直接使用sql查詢接口。也許這種做法更加合理。
使用介紹
1.配置文件配置好連接串
connectionName的值對應連接串的name
 <appSettings>
    <add key="connectionName" value="DB"/>
  </appSettings>
  <connectionStrings>
    <!--<add name="DB" connectionString="Data Source=localhost/XE;User Id=hr;Password=hr;" providerName="Oracle.ManagedDataAccess" />-->
    <!--<add name="DB" connectionString="host=localhost;database=test;uid=root;pwd=sa123456;charset=utf8;" providerName="MySql.Data.MySqlClient" />-->
    <add name="DB" connectionString="Data Source=localhost;Initial Catalog=test;Persist Security Info=True;User ID=sa;Password=123456;" providerName="System.Data.SqlClient" />
</connectionStrings> 
        
2.定義好實體
public class Book { [Key(IsAutoGenerated = true)] public int? BookID { get; set; } public string BookName { get; set; } public int? AuthorID { get; set; } [NotColumn] public string AuthorName { get; set; } public double? Price { get; set; } public DateTime? PublishDate { get; set; } }
增刪改查 目前支持sqlserver、mysql、oracle、sqlite
Add
using (DNetContext db = new DNetContext()) { var authorid = db.Add(new Author { AuthorName = "張三", Age = 30, IsValid = true }); db.Add(new Book { BookName = "從入門到放棄", Price = 20.5, PublishDate = DateTime.Now, AuthorID = authorid }); }
Update
更新總共有三種方式
1.傳入一個實體,實體中的非null屬性都會被更新,這是 一次安全的更新,因為如果不做這個判斷,那么使用者傳入一個實體的時候很可能初衷是只更新所賦值的那幾個字段,但是卻把其余未賦值的字段全部NULL化了,這就是一次很危險的操作。但是這同時帶來了一個問題,就是通過實體更新無法更新一個字段為null,這時候解決方式可以是采用下面介紹的另外兩種方式進行更新,也可以使用
db.UpdateOnlyFields<Author>(new Author { AuthorName = "123", Age = 20, AuthorID = 1, IsValid = true }, m => m, m => m.AuthorID == 1);
來強制更新指定的字段,相反如果不想更新實體中的特殊字段可以使用
db.UpdateIgnoreFields<Author>(new Author { AuthorName = "123", Age = 20, AuthorID = 1, IsValid = true }, m => m.AuthorName, m => m.AuthorID == 1);
2.傳入一個Action<T> 類型的參數,此類型參數用於直接賦予變量,使用起來會很方便,譬如db.Update<Author>(m => m.AuthorName = "jack", m => m.AuthorID == authorid);但是缺點是無法依賴列進行更新
3.傳入Expression<Func<T, T>>類型的參數,這是一個構造實體類的操作,這種寫法會稍微麻煩一點,但是功能卻是最強大的,支持依賴列進行更新,同時所有賦予的字段都會被更新,譬如:db.Update<Author>(m => new Author { AuthorName = m.AuthorName + "123", IsValid = null }, m => m.AuthorID == 1);
所以使用者在實際情況中根據需求來使用,一般情況下第二種方式完全滿足開發場景了,特殊的情況使用第三種方式
using (DNetContext db = new DNetContext()) {
int authorid = db.GetMax<Author>(m => (int)m.AuthorID); db.Update<Author>(m => m.AuthorName = "jack", m => m.AuthorID == authorid); }
Delete
using (DNetContext db = new DNetContext()) { var author = db.GetSingle<Author>(m => true, q => q.OrderBy(m => m.AuthorID)); var effect = db.Delete(author); int authorid = db.GetMax<Author>(m => (int)m.AuthorID); db.Delete<Author>(m => m.AuthorID == authorid); }
Query
單表查詢
支持以下sql格式
like 
Contains、StartsWith、EndsWith
db.GetList<Author>(m => m.AuthorName.StartsWith("張三") && m.IsValid == true);
  
        in 
Contains 集合類
upper lower
ToUpper、ToLower
sql字符大小比較
CompareTo、Equals
var authors= db.GetList<Author>(m => m.AuthorName.CompareTo("123")>0 && m.IsValid == true);
charindex instr
IndexOf
var authors= db.GetList<Author>(m => m.AuthorName.IndexOf("123")>=0 && m.IsValid == true);
is null or = ''
IsNullOrEmpty
var authors= db.GetList<Author>(m =>string.IsNullOrEmpty(m.AuthorName) && m.IsValid == true);
類型轉化、時間格式化
ToString
var authors= db.GetList<Book>(m =>((DateTime)m.PublishDate).ToString("yyyy-MM-dd")=="2017-10-11");
字符轉時間
ToDateTime
var authors= db.GetList<Book>(m =>Convert.ToDateTime(m.PublishDate)>DateTime.Now.AddDays(-10));
整型轉化
ToInt32
trim
TrimStart、TrimEnd、Trim
using (DNetContext db = new DNetContext()) { var author = db.GetSingle<Author>(m => true, q => q.OrderBy(m => m.AuthorID)); author = db.GetSingle<Author>(m => m.AuthorName.Contains("李四") && m.IsValid == true); var authors= db.GetList<Author>(m => m.AuthorName.StartsWith("張三") && m.IsValid == true); //獲取動態類型 List<dynamic> name = db.GetDistinctList<Author>(m => m.AuthorName.StartsWith("王五") && m.IsValid == true,m=>m.AuthorName); List<string> name1 = db.GetDistinctList<Author,string>(m => m.AuthorName.StartsWith("王五") && m.IsValid == true, m => m.AuthorName);
//子查詢寫法
var books = db.GetList<Book>(m => SubQuery.GetList<Author>(n => n.AuthorID > 10, n => n.AuthorID).Contains(m.AuthorID));
books = db.GetList<Book>(m => m.AuthorID >= SubQuery.GetSingle<Author>(n => n.AuthorID == 10, n => n.AuthorID));
//獲取最大值 var authorid = db.GetMax<Author>(m => (int)m.AuthorID); //動態查詢 WhereBuilder<Author> where = new WhereBuilder<Author>(); where.And(m=>m.AuthorName.Contains("張三")); where.And(m => m.AuthorID==3); where.Or(m=>m.IsValid==true); db.GetList<Author>(where.WhereExpression); //分頁參數由前台傳來 PageFilter<Author> page = new PageFilter<Author> { PageIndex = 1, PageSize = 10 };
page.And(m => "jim green".Contains(m.AuthorName));
page.OrderBy(q => q.OrderBy(m => m.AuthorName).OrderByDescending(m => m.AuthorID));
PageDataSource<Author> pageSource = db.GetPage<Author>(page); }
JOIN Query  僅用於演示
join query支持兩種方式,不限制參數別名JoinQuery和限制參數別名 JoinQueryAlias,譬如查詢a b c 三張不同的表可以不限制別名,如果查詢a b a 存在相同的表的時候就必須限制參數別名
var join = db.JoinQueryAlias.LeftJoin<Book, Author>((m, n) => m.AuthorID == n.AuthorID && n.IsValid == true) .InnerJoin<Book, Author>((m1, n) => m1.AuthorID == n.AuthorID && n.IsValid == true) .Fields<Book>(m1 => new Book { BookName=m1.BookName+"123" }) .OrderByAsc<Book>(m => m.BookName); PageFilter page = new PageFilter { PageIndex = 1, PageSize = 10 };//分頁參數前台傳來 join.GetPage<Book>(page);
using (DNetContext db = new DNetContext()) { var books = db.JoinQuery.LeftJoin<Book, Author>((m, n) => m.AuthorID == n.AuthorID && n.IsValid == true) .Fields<Book, Author>((m, n) => new { m.BookName, AuthorName = SqlFunctions.Count(n.AuthorName) }) .OrderByAsc<Book>(m => m.BookName) .GroupBy<Book, Author>((m, n) => new { m.BookName, n.AuthorName }) .Where<Book, Author>((m, n) => m.Price > 10 && n.IsValid == true) .GetList<Book>(); var join = db.JoinQuery.LeftJoin<Book, Author>((m, n) => m.AuthorID == n.AuthorID && n.IsValid == true) .Fields<Book, Author>((m, n) => new { m, n.AuthorName }) .OrderByAsc<Book>(m => m.BookName); PageFilter page = new PageFilter { PageIndex = 1, PageSize = 10 };//分頁參數前台傳來 join.GetPage<Book>(page); }
采用這種鏈式的寫法,更接近於寫一條sql的思路和方式,沒有語法包袱,使用者會很快上手,通過Fields方式指定查詢字段更方便獲取一整張表的字段
SQL Query
            using (DNetContext db = new DNetContext()) { StringBuilder sql = new StringBuilder(); List<DbParameter> parameters = new List<DbParameter>(); sql.AppendFormat(@"SELECT {0},A.AuthorName FROM Book B LEFT JOIN Author A ON A.AuthorID=B.AuthorID WHERE", SqlBuilder.GetSelectAllFields<Book>("B")); sql.Append(" B.BookID>@BookID "); parameters.Add(db.GetDbParameter("BookID",1)); PageDataSource<Book> books = db.GetPage<Book>(sql.ToString(),new PageFilter { PageIndex=1, PageSize=5 }, parameters.ToArray()); List<Book> bks = db.GetList<Book>(sql.ToString(), parameters.ToArray()); } 
        
DbTransaction
using (DNetContext db = new DNetContext()) { db.DataBase.BeginTransaction(); try { List<Author> authors = new List<Author>(); for (int i = 0; i <= 100; i++) { authors.Add(new Author { AuthorName = "測試" + i.ToString(), Age = 20, IsValid = true }); } db.Add(authors); db.DataBase.Commit(); } catch { db.DataBase.Rollback(); } }
Distributed Transaction
DNetTransaction transaction = new DNetTransaction(); transaction.BeginTransaction(); try { using (DNetContext db = new DNetContext()) { List<Author> authors = new List<Author>(); for (int i = 0; i <= 100; i++) { authors.Add(new Author { AuthorName = "測試" + i.ToString(), Age = 20, IsValid = true }); } db.Add(authors); transaction.Commit(); } } catch { transaction.Rollback(); }
歡迎技術討論 如有疑問可以在評論區討論
源碼地址
https://github.com/DNetORM/DNetORM4.0
