PDF.NET SOD框架不只僅是一個ORM,可是它的ORM功能是獨具特點的,我在博客中已經屢次介紹,但都是原理性的,可能很多初學的朋友仍是以爲複雜,其實,SOD的ORM是很簡單的。下面咱們就採用流行的 Code First的方式,一步步來了解下。html
首先創建一個控制檯項目(支持.NET2.0的項目),並使用程序包管理器添加PDF.NET SOD的程序引用:前端
PM> Install-Package PDF.NET.SODgit
更多詳細使用信息說明,請參考nuget 網站說明 https://www.nuget.org/packages/PDF.NET/github
新建一個控制檯項目,添加一個應用程序配置文件,增長一個數據庫鏈接配置:sql
<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <add name="local" connectionString="Data Source=.;Initial Catalog=LocalDB;Integrated Security=True" providerName="SqlServer" /> </connectionStrings> </configuration>
上面的鏈接字符串要求你本地已經安裝SqlServer,框架兼容2000以上全部版本,有一個數據庫名字是 LocalDB。固然你也能夠修改爲你實際的鏈接字符串。數據庫
以後,咱們的查詢示例,都將採用這個鏈接配置。安全
注意:最新版本的SOD框架,若是使用的是SqlServer,而且鏈接字符串指定了數據庫名字但實際上沒有這個數據庫,框架能夠自動建立數據庫,此功能須要SOD的Code First功能支持,請參考下面「1.5 ,建立數據庫表」的功能。框架
SOD框架最基本的配置,僅須要這一個地方,這比起EF來講要簡單。ide
若是是SqlServer +EF Code First方式的鏈接配置,SOD框架也可使用它這個鏈接字符串的。svn
咱們將使用最多見的用戶登陸來舉例,這裏須要一個用戶實體類,假設它的定義是下面這個樣子的:
public class User : EntityBase { public User() { TableName="Tb_User"; IdentityName = "UserID"; PrimaryKeys.Add("UserID"); } public int ID { get { return getProperty<int>("UserID"); } set { setProperty("UserID", value); } } public string Name { get { return getProperty<string>("Name"); } set { setProperty("Name", value, 50); } } public string Pwd { get { return getProperty<string>("Pwd"); } set { setProperty("Pwd", value, 50); } } public DateTime RegistedDate { get { return getProperty<DateTime>("RegistedDate"); } set { setProperty("RegistedDate", value); } } }
在上面的定義中,構造函數內指明瞭 IdentityName = "UserID";這表示當前實體類對應的表有一個叫作 UserID的自增列,每當插入實體類後,能夠經過該自增列對應的屬性獲取到新插入的自增ID的值。
另外,咱們發現每一個實體類的屬性中,都是這樣的寫法:
public int ID { get { return getProperty<int>("UserID"); } set { setProperty("UserID", value); } }
屬性內 getProperty ,setProperty 方法內的第一個參數,就是屬性對應的字段名字。
因此,這樣的屬性,SOD框架稱爲「持久化屬性」。
能夠看到,SOD實體類仍是比較簡單的,它沒有使用特性來申明數據庫信息,這意味着你能夠在運行時修改實體類影射的主鍵,自增字段,表名稱等數據庫元數據,而且不須要反射,這些特性構成了SOD框架簡單而強大的基礎。
在項目中添加一個 LocalDbContext.cs 文件,文件中添加以下代碼,以便檢查表 Tb_User 是否存在,若是不存在,則自動建立一個:
/// <summary> /// 用來測試的本地SqlServer 數據庫上下文類 /// </summary> public class LocalDbContext : DbContext { public LocalDbContext() : base("local") { //local 是鏈接字符串名字 } #region 父類抽象方法的實現 protected override bool CheckAllTableExists() { //建立用戶表 CheckTableExists<User>(); return true; } #endregion }
本例中使用SqlServer 做爲查詢示例,程序會自動使用 SqlServerDbContext 密封類來進行內部協做處理,但這取決於你的AdoHelper實例類型,若是是Oracle,則內部使用的是OracleDbContext 密封類。
若是你不須要ORM的 Code First功能,這個 DbContext 實現類是不須要寫的。
OK,基本準備就緒,如今Main 方法裏面能夠寫下面的代碼開始工做了:
LocalDbContext context = new LocalDbContext();//自動建立表
準備工做所有完成,運行這一句代碼,以後查看SqlServer管理工具,發現表 Tb_User 已經建立了。
SOD框架的ORM功能跟一般的ORM框架不一樣,SOD框架的實體類上並無數據查詢和持久化的方法,因此SOD的實體類是「很是純粹的」實體類,你能夠把它看做是一個數據容器,或者用來看成DTO,ViewModel使用,有關這個話題更詳細的闡述,請看這篇文章:《DataSet的靈活,實體類的方便,DTO的效率:SOD框架的數據容器,打造最適合DDD的ORM框架》。
在進行真正的數據查詢以前,得先有數據,因此咱們先測試數據的增刪改。
首先刪除以前的測試數據,能夠採用OQL進行批量數據刪除:
int count = 0; //刪除 測試數據----------------------------------------------------- User user = new User(); OQL deleteQ = OQL.From(user) .Delete() .Where(cmp => cmp.Comparer(user.ID, ">", 0)) //爲了安全,不帶Where條件是不會所有刪除數據的 .END; count= EntityQuery<User>.ExecuteOql(deleteQ, context.CurrentDataBase);
這裏將用戶ID 大於0的數據所有刪除了,框架內置了數據安全機制,不會隨意刪除所有數據,因此爲了清除所有數據,採用了上面的方法。
方式1,採用DbContext 的Add 方法:
count = 0; User zhang_san = new User() { Name = "zhang san", Pwd = "123" }; count += context.Add<User>(zhang_san);//採用 DbContext 方式插入數據
方式2,採用OQL:
User li_si = new User() { Name = "li si", Pwd = "123" }; OQL insertQ= OQL.From(li_si) .Insert(li_si.Name);//僅僅插入用戶名,不插入密碼
OQL還需EntityQuery 對象配合,才能夠執行,繼續看下面的代碼:
AdoHelper db = MyDB.GetDBHelperByConnectionName("local"); EntityQuery<User> userQuery = new EntityQuery<User>(db); count += userQuery.ExecuteOql(insertQ);
下面是結果圖:
方式3,直接EntityQuery 插入實體類:
User zhang_yeye = new User() { Name = "zhang yeye", Pwd = "456" }; count += EntityQuery<User>.Instance.Insert(zhang_yeye);//採用泛型 EntityQuery 方式插入數據
方式1,採用 DbContext 方式更新數據
li_si.Pwd = "123123"; count = context.Update<User>(li_si);//採用 DbContext 方式更新數據
方式2,採用OQL方式更新指定的數據
li_si.Pwd = "123456"; OQL updateQ= OQL.From(li_si) .Update(li_si.Pwd) //僅僅更新密碼 .END; count += EntityQuery<User>.Instance.ExecuteOql(updateQ);//採用OQL方式更新指定的數據
方式3,採用泛型 EntityQuery 方式修改數據
li_si.Pwd = "888888"; count += EntityQuery<User>.Instance.Update(li_si);//採用泛型 EntityQuery 方式修改數據
前面增刪改數據完成了,如今有了測試數據,咱們能夠來進行ORM的數據查詢測試了,這裏使用用戶登陸的例子來測試,框架提供了6種數據查詢方式。
假設前端直接傳遞了一個 User 實體類對象,中間設置了用戶名和密碼,如今有一個登陸方法使用該對象,該方法詳細內容以下所示:
/// <summary> /// 使用用戶對象來登陸,OQL最簡單最多見的使用方式 /// </summary> /// <param name="user"></param> /// <returns></returns> public bool Login(User user) { OQL q = OQL.From(user) .Select() .Where(user.Name, user.Pwd) //以用戶名和密碼來驗證登陸 .END; User dbUser =q.ToEntity<User>();//ToEntity,OQL擴展方法 return dbUser != null; //查詢到用戶實體類,表示登陸成功 }
這裏咱們使用了SOD框架的ORM查詢語言--OQL,它的結構很是相似於SQL,你能夠認爲OQL就是對象化的SQL語句。
OQL表達式採用 .From.....END 的語法,對象的鏈式方法調用,只要敲點出來的就是正確的,這樣沒有SQL基礎的同窗也能夠很快掌握該查詢語法,也能立刻做數據開發。
注意:在本例中,使用了OQL的擴展方法,所以須要引用下面的名字空間:
using PWMIS.Core.Extensions;
若是不使用擴展方法,能夠採用泛型EntityQuery 的方法,請看下面的示例。
/// <summary> /// 使用用戶對象來登陸,可是使用 OQLCompare 對象的 EqualValue 相等比較方式 /// </summary> /// <param name="user"></param> /// <returns></returns> public bool Login1(User user) { OQL q = OQL.From(user) .Select(user.ID) //僅查詢一個屬性字段 ID .Where(cmp => cmp.EqualValue(user.Name) & cmp.EqualValue(user.Pwd)) .END; User dbUser = EntityQuery<User>.QueryObject(q); return dbUser != null; //查詢到用戶實體類,表示登陸成功 }
跟例1同樣,這裏也要求user 對象的Name和Pwd屬性必須事先有值。本例沒有使用OQL的擴展方法。
本例只是對例子1作了下改進,重點在於登陸方法的參數不是用戶對象,而是名字和密碼參數。
/// <summary> /// 使用用戶名密碼參數來登陸,採用 EntityQuery 泛型查詢方法 /// </summary> /// <param name="name"></param> /// <param name="pwd"></param> /// <returns></returns> public bool Login2(string name, string pwd) { User user = new User() { Name = name, Pwd = pwd }; OQL q = OQL.From(user) .Select(user.ID) .Where(user.Name, user.Pwd) .END; User dbUser = EntityQuery<User>.QueryObject(q); return dbUser != null; //查詢到用戶實體類,表示登陸成功 }
/// <summary> /// 使用用戶名密碼參數來登陸,使用早期的實例化OQL對象的方式,並使用OQLConditon 對象爲查詢條件 /// </summary> /// <param name="name"></param> /// <param name="pwd"></param> /// <returns></returns> public bool Login3(string name, string pwd) { User user = new User(); OQL q = new OQL(user); q.Select(user.ID).Where(q.Condition.AND(user.Name, "=", name).AND(user.Pwd, "=", pwd)); User dbUser = EntityQuery<User>.QueryObject(q); return dbUser != null; //查詢到用戶實體類,表示登陸成功 }
這是OQL早期的條件查詢方式,缺點是無法構造複雜的查詢條件。
OQLCompare 的操做符重載能夠簡化比較條件,以下所示:
/// <summary> /// 使用用戶名密碼參數來登陸,並使用操做符重載的查詢條件比較方式 /// </summary> /// <param name="name"></param> /// <param name="pwd"></param> /// <returns></returns> public bool Login4(string name, string pwd) { User user = new User(); OQL q = OQL.From(user) .Select() .Where( cmp => cmp.Property(user.Name) == name & cmp.Property(user.Pwd) == pwd ) .END; User dbUser = EntityQuery<User>.QueryObject(q); return dbUser != null; //查詢到用戶實體類,表示登陸成功 }
使用泛型OQL查詢(GOQL),對於單實體類查詢最簡單的使用方式,缺點是不能進行「連表查詢」,即多個實體類聯合查詢。
/// <summary> /// 使用用戶名密碼參數來登陸,使用泛型OQL查詢(GOQL),對於單實體類查詢最簡單的使用方式。 /// </summary> /// <param name="name"></param> /// <param name="pwd"></param> /// <returns></returns> public bool Login5(string name, string pwd) { User dbUser = OQL.From<User>() .Select() .Where((cmp, user) => cmp.Property(user.Name) == name & cmp.Property(user.Pwd) == pwd ) .END .ToObject(); return dbUser != null; //查詢到用戶實體類,表示登陸成功 }
SOD實體類的「主鍵」字段是能夠修改的,這樣你能夠隨時修改它,就像實體類原本的主鍵同樣,用它來填充數據,本例就是判斷是否填充成功當前實體類來判斷用戶是否能夠登陸。
/// <summary> /// 使用用戶名密碼參數來登陸,可是根據實體類的主鍵來填充實體類並判斷是否成功。 /// </summary> /// <param name="name"></param> /// <param name="pwd"></param> /// <returns></returns> public bool Login6(string name, string pwd) { User user = new User(); user.PrimaryKeys.Clear(); user.PrimaryKeys.Add("Name"); user.PrimaryKeys.Add("Pwd"); user.Name = name; user.Pwd = pwd; bool result= EntityQuery<User>.Fill(user);//靜態方法,使用默認的鏈接對象 return result; }
前面的例子都只是查詢一條數據,若是須要查詢多條數據也很簡單,參見下面的例子,如何查詢全部姓 zhang 的用戶:
/// <summary> /// 模糊查詢用戶,返回用戶列表,使用OQLCompare 委託 /// </summary> /// <param name="likeName">要匹配的用戶名</param> /// <returns>用戶列表</returns> public List<User> FuzzyQueryUser(string likeName) { User user = new User(); OQL q = OQL.From(user) .Select() .Where(cmp => cmp.Comparer(user.Name, "like", likeName+"%") ) .END; List<User> users = EntityQuery<User>.QueryList(q); return users; }
前端調用:
//查詢列表 var users=service.FuzzyQueryUser("zhang"); Console.WriteLine("模糊查詢姓 張 的用戶,數量:{0}",users.Count );
因此,查詢多條數據,僅須要使用泛型 EntityQuery對象的QueryList 方法便可。一樣,框架也爲你提供了OQL對象擴展方法來直接查詢列表數據。
這裏再也不舉例,個人博客文章也屢次說明過,請參考下面這個系列文章:
SOD框架的整個設計都採用了「條條道路通羅馬」的原則,即多模式解決方案,對數據的開發不論是SQL-MAP ,ORM,Data Control 哪一種模式均可以「異曲同工」,對於OQL,這個也獲得了充分的體現,好比上面的用戶登陸功能,使用了7 種方式來實現,實際上還有3中查詢方式本篇文章沒有作成說明;而對於實體類的增,刪,改,分別又提供了DbContext,OQL,泛型EntityQuery 等多種方式。
因此,SOD框架的使用很是靈活,你能夠根據你的偏好,習慣,環境,來靈活使用,並且也容易擴展,所以,相對於EF這樣的ORM框架來,SOD框架的ORM功能沒有任何束縛,它自由,靈活,並且輕量,容易擴展,但不妨礙它的強大,好比對於分表分庫的查詢,數據的批量更新插入修改,數據庫鎖的直接支持等這些「企業級」數據開發需求的支持。
本篇文章的源碼,已經上傳在了框架的開源項目 pwmis.codeplex.com 網站上,能夠經過下面的地址查看完整的源碼:
http://pwmis.codeplex.com/SourceControl/latest#SOD/Test/SampleORMTest/Program.cs
源碼下載,能夠在下面的地址查看:
http://pwmis.codeplex.com/releases/view/117822 簡單ORM示例程序--新手必讀
有關框架更詳細而完整的入門指引,請參考下面這篇文章:
PDF.NET SOD 開源框架紅包派送活動 && 新手快速入門指引
更多完整而詳細的信息,請看框架官網地址:
框架已經徹底開源,參看這篇文章:
一年之計在於春,2015開篇:PDF.NET SOD Ver 5.1徹底開源
另外,網友 廣州-四糸奈 在他的"驚鴻哥的港灣"寫了一篇基礎入門介紹文章《PDF.NET最初等入門》,推薦你們看看。
網友 廣州-銀古 寫了一篇《SOD讓你的舊代碼煥發青春》,講述瞭如何改造老式僵化項目的過程,推薦你們看看。
CodePlex online : http://pwmis.codeplex.com/SourceControl/latest
CodePlex SVN : https://pwmis.codeplex.com/svn
GitHub : https://github.com/znlgis/PDF.NET-SOD
OSChina : http://git.oschina.net/dxzyx/SOD