注冊博客園帳號也有好幾年了,之前注冊帳號主要是為了看別人的文章下載東西的時候方便。從來沒有寫過什麼博客,一直以為只要注冊了帳號就可以寫博客,最近用到了才發現還得申請一下,於是就申請了博客,算了也不扯這麼多沒用的了,直接進入主題吧!
網上開源的ORM工具也不少,開源中國上就有不少,很多都下載試用過,不過感覺用起來都不是很方便,園子裡面也有不少人分享自己寫的ORM工具,用過一個叫 MySoft.Data 的ORM工具,感覺裡面的鏈式調用函數的寫法不錯,但是用起來感覺也有些不如意的地方,於是某個周末的晚上自己研究人家的代碼就想著自己來實現一個ORM工具,又扯遠了...
自己弄得這個ORM工具也不知道起什麼名字好,於是就直接就叫 ORM,寫這個的時候參考過 MySoft.Data、 NBearLite、PetaPoco ,整個設計的感覺不算太好,反正就是憑著自己的感覺來寫的, 接口用的比較少,抽象類用到的比較多,支持多數據庫,但是只在SqlServer和SQLite中測試過,其他數據庫還沒有測試,可以實現較復雜的查詢,增刪改、事務等操作,ORM沒有經過系統的測試,也就是自己寫些小例子測試一下,所以穩定性、性能方面不敢保證,建議大家先不要用到項目中去,大家可以下載代碼自己改改、測試測試然後再在項目中使用。
下面說下用法吧,ORM 中所有類都用的一個命名空間就叫 ORM,只是在代碼中對不能作用的類做了些分類放在不同文件夾,但都是一個命名空間。
首先要創建一個 IDbSession 對象:
<!--數據庫連接字符串如下--> <add name="connStr" connectionString="Data Source=.;Initial Catalog=dbName;Persist Security Info=True;User ID=sa;Password=******" providerName="System.Data.SqlClient"/>
IDbSession db = DbSession.New('connStr');
生成實體類:
namespace ORM.Demo.Model { using System; using ORM; public partial class SysUser2Role : TableEntity { private Guid? _SysUser2RoleOID; /// <summary> /// SysUser2RoleOID /// </summary> public Guid? SysUser2RoleOID { get { return _SysUser2RoleOID; } set { _SysUser2RoleOID = value; } } private static NormalField __SysUser2RoleOID = new NormalField("SysUser2Role", "SysUser2RoleOID"); /// <summary> /// SysUser2RoleOID /// </summary> [PrimaryKey()] public static NormalField SysUser2RoleOID_ { get { return __SysUser2RoleOID; } } private string _SysUserOID; /// <summary> /// SysUserOID /// </summary> public string SysUserOID { get { return _SysUserOID; } set { _SysUserOID = value; } } private static NormalField __SysUserOID = new NormalField("SysUser2Role", "SysUserOID"); /// <summary> /// SysUserOID /// </summary> public static NormalField SysUserOID_ { get { return __SysUserOID; } } private string _SysRoleOID; /// <summary> /// SysRoleOID /// </summary> public string SysRoleOID { get { return _SysRoleOID; } set { _SysRoleOID = value; } } private static NormalField __SysRoleOID = new NormalField("SysUser2Role", "SysRoleOID"); /// <summary> /// SysRoleOID /// </summary> public static NormalField SysRoleOID_ { get { return __SysRoleOID; } } private string _CreateUserOID; /// <summary> /// CreateUserOID /// </summary> public string CreateUserOID { get { return _CreateUserOID; } set { _CreateUserOID = value; } } private static NormalField __CreateUserOID = new NormalField("SysUser2Role", "CreateUserOID"); /// <summary> /// CreateUserOID /// </summary> public static NormalField CreateUserOID_ { get { return __CreateUserOID; } } private DateTime? _UpdateTime; /// <summary> /// UpdateTime /// </summary> public DateTime? UpdateTime { get { return _UpdateTime; } set { _UpdateTime = value; } } private static NormalField __UpdateTime = new NormalField("SysUser2Role", "UpdateTime"); /// <summary> /// UpdateTime /// </summary> public static NormalField UpdateTime_ { get { return __UpdateTime; } } private static FieldAll _All; public static FieldAll All { get { _All = _All ?? new FieldAll(typeof(SysUser2Role)); return _All; } } } } namespace ORM.Demo.Model { using System; using ORM; public partial class SysRole : TableEntity { private Guid? _SysRoleOID; /// <summary> /// SysRoleOID /// </summary> public Guid? SysRoleOID { get { return _SysRoleOID; } set { _SysRoleOID = value; } } private static NormalField __SysRoleOID = new NormalField("SysRole", "SysRoleOID"); /// <summary> /// SysRoleOID /// </summary> [PrimaryKey()] public static NormalField SysRoleOID_ { get { return __SysRoleOID; } } private string _RoleName; /// <summary> /// RoleName /// </summary> public string RoleName { get { return _RoleName; } set { _RoleName = value; } } private static NormalField __RoleName = new NormalField("SysRole", "RoleName"); /// <summary> /// RoleName /// </summary> public static NormalField RoleName_ { get { return __RoleName; } } private string _CreateUserOID; /// <summary> /// CreateUserOID /// </summary> public string CreateUserOID { get { return _CreateUserOID; } set { _CreateUserOID = value; } } private static NormalField __CreateUserOID = new NormalField("SysRole", "CreateUserOID"); /// <summary> /// CreateUserOID /// </summary> public static NormalField CreateUserOID_ { get { return __CreateUserOID; } } private string _Remark; /// <summary> /// Remark /// </summary> public string Remark { get { return _Remark; } set { _Remark = value; } } private static NormalField __Remark = new NormalField("SysRole", "Remark"); /// <summary> /// Remark /// </summary> public static NormalField Remark_ { get { return __Remark; } } private DateTime? _UpdateTime; /// <summary> /// UpdateTime /// </summary> public DateTime? UpdateTime { get { return _UpdateTime; } set { _UpdateTime = value; } } private static NormalField __UpdateTime = new NormalField("SysRole", "UpdateTime"); /// <summary> /// UpdateTime /// </summary> public static NormalField UpdateTime_ { get { return __UpdateTime; } } private static FieldAll _All; public static FieldAll All { get { _All = _All ?? new FieldAll(typeof(SysRole)); return _All; } } } } namespace ORM.Demo.Model { using System; using ORM; public partial class SysUser2Role : TableEntity { private Guid? _SysUser2RoleOID; /// <summary> /// SysUser2RoleOID /// </summary> public Guid? SysUser2RoleOID { get { return _SysUser2RoleOID; } set { _SysUser2RoleOID = value; } } private static NormalField __SysUser2RoleOID = new NormalField("SysUser2Role", "SysUser2RoleOID"); /// <summary> /// SysUser2RoleOID /// </summary> [PrimaryKey()] public static NormalField SysUser2RoleOID_ { get { return __SysUser2RoleOID; } } private string _SysUserOID; /// <summary> /// SysUserOID /// </summary> public string SysUserOID { get { return _SysUserOID; } set { _SysUserOID = value; } } private static NormalField __SysUserOID = new NormalField("SysUser2Role", "SysUserOID"); /// <summary> /// SysUserOID /// </summary> public static NormalField SysUserOID_ { get { return __SysUserOID; } } private string _SysRoleOID; /// <summary> /// SysRoleOID /// </summary> public string SysRoleOID { get { return _SysRoleOID; } set { _SysRoleOID = value; } } private static NormalField __SysRoleOID = new NormalField("SysUser2Role", "SysRoleOID"); /// <summary> /// SysRoleOID /// </summary> public static NormalField SysRoleOID_ { get { return __SysRoleOID; } } private string _CreateUserOID; /// <summary> /// CreateUserOID /// </summary> public string CreateUserOID { get { return _CreateUserOID; } set { _CreateUserOID = value; } } private static NormalField __CreateUserOID = new NormalField("SysUser2Role", "CreateUserOID"); /// <summary> /// CreateUserOID /// </summary> public static NormalField CreateUserOID_ { get { return __CreateUserOID; } } private DateTime? _UpdateTime; /// <summary> /// UpdateTime /// </summary> public DateTime? UpdateTime { get { return _UpdateTime; } set { _UpdateTime = value; } } private static NormalField __UpdateTime = new NormalField("SysUser2Role", "UpdateTime"); /// <summary> /// UpdateTime /// </summary> public static NormalField UpdateTime_ { get { return __UpdateTime; } } private static FieldAll _All; public static FieldAll All { get { _All = _All ?? new FieldAll(typeof(SysUser2Role)); return _All; } } } }
這個 IDbSession 最好每個數據庫只實例化一個,然後用個靜態變量保存就行了,上面三個類分別是 用戶表、角色表、用戶角色關系表生成的類,
下面是些查詢的示例:
//可以生成一個SQL對象 SelectSQL sql = db.SFrom<SysUser>().Where(SysUser.LoginName_.Like('%a%')).Select(SysUser.PersonName_).ToSQL(); string str = sql.ToString();
/*
SELECT [SysUser].[PersonName] FROM [SysUser] WHERE [SysUser].[LoginName] LIKE '%a%'
@P_7183594707124d339902badd64347c30: %a%
*/
//也可以直接執行查詢生成 List<SysUser> List<SysUser> list = db.SFrom<SysUser>().Where(SysUser.LoginName.Like('%a%')).ToList<SysUser>(); //也可以直接執行查詢生成 DataTable DataTable tb = db.SFrom<SysUser>().Where(SysUser.LoginName.Like('%a%')).ToDataTable();
//多表分頁查詢
PageSQL sql = db.SFrom<SysUser>()
.InnerJoin<SysUser2Role>(SysUser.SysUserOID_ == SysUser2Role.SysUserOID_)
.InnerJoin<SysRole>(SysUser2Role.SysRoleOID_ == SysRole.SysRoleOID_)
.Where(SysUser.LoginName_ == 'admin')
.ToPageSQL(100, 0);
int total = 0;
List<SysRole> list = db.SFrom<SysUser>()
.InnerJoin<SysUser2Role>(SysUser.SysUserOID_ == SysUser2Role.SysUserOID_)
.InnerJoin<SysRole>(SysUser2Role.SysRoleOID_ == SysRole.SysRoleOID_)
.Where(SysUser.LoginName_ == 'admin')
.ToPageList<SysRole>(100, 0, out total);
下面有個復雜的語句設計到多表查詢、Union、子查詢等:
var sql = this.Db.SFrom( this.Db.SFrom<M.SysMenu>() .InnerJoin<M.SysUser2Menu>(M.SysUser2Menu.SysMenuOID_ == M.SysMenu.SysMenuOID_) .Where(M.SysUser2Menu.SysUserOID_ == useroid && (M.SysMenu.ShowMenu_ == 1 || M.SysMenu.ShowMenu_.IsNull())) .Select(M.SysMenu.All) .ToSQL() .Union(this.Db.SFrom<M.SysMenu>() .InnerJoin<M.SysRole2Menu>(M.SysRole2Menu.SysMenuOID_ == M.SysMenu.SysMenuOID_) .Where( M.SysRole2Menu.SysRoleOID_.In(this.Db.SFrom<M.SysUser2Role>() .Where(M.SysUser2Role.SysUserOID_ == useroid) .Select(M.SysUser2Role.SysRoleOID_) .ToSQL() .Union(this.Db.SFrom<M.SysGroup2Role>() .InnerJoin<M.SysGroup2User>(M.SysGroup2Role.SysGroupOID_ == M.SysGroup2User.SysGroupOID_) .Where(M.SysGroup2User.SysUserOID_ == useroid) .Select(M.SysGroup2Role.SysRoleOID_) .ToSQL() ) ) && (M.SysMenu.ShowMenu_ == 1 || M.SysMenu.ShowMenu_.IsNull()) ) .Select(M.SysMenu.All) .ToSQL() ), "A" ) .LeftJoin<M.SysUserMenuTemp>(SQLEntity.Set["A"]["SysMenuOID"] == M.SysUserMenuTemp.SysMenuOID_) .OrderBy(OrderBy.New(M.SysUserMenuTemp.SortNumber_).Add(SQLEntity.Set["A"]["SortNumber"])) .Select(SQLEntity.Set["A"], M.SysUserMenuTemp.SortNumber_, M.SysUserMenuTemp.OpenState_) .ToSQL(); db.ToList<M.SysMenu>(sql);
最終生成 SQL 語句如下:
SELECT [A].[SysMenuOID],[A].[ParentMenuOID],[A].[CreateUserOID],[A].[MenuText],[A].[MenuIconUrl],[A].[MenuAction],[A].[OtherScript],[A].[MenuType],[A].[Remark],[A].[ShowMenu],[A].[SortNumber],[A].[OpenState],[A].[UpdateTime],[SysUserMenuTemp].[SortNumber],[SysUserMenuTemp].[OpenState] FROM (SELECT [SysMenu].[SysMenuOID],[SysMenu].[ParentMenuOID],[SysMenu].[CreateUserOID],[SysMenu].[MenuText],[SysMenu].[MenuIconUrl],[SysMenu].[MenuAction],[SysMenu].[OtherScript],[SysMenu].[MenuType],[SysMenu].[Remark],[SysMenu].[ShowMenu],[SysMenu].[SortNumber],[SysMenu].[OpenState],[SysMenu].[UpdateTime] FROM [SysMenu] INNER JOIN [SysUser2Menu] ON [SysUser2Menu].[SysMenuOID]=[SysMenu].[SysMenuOID] WHERE [SysUser2Menu].[SysUserOID]=@P_43063492ed5a467ab0dddd9043a5e4c8 AND ([SysMenu].[ShowMenu]=@P_7183594707124d339902badd64347c30 OR [SysMenu].[ShowMenu] IS NULL) UNION SELECT [SysMenu].[SysMenuOID],[SysMenu].[ParentMenuOID],[SysMenu].[CreateUserOID],[SysMenu].[MenuText],[SysMenu].[MenuIconUrl],[SysMenu].[MenuAction],[SysMenu].[OtherScript],[SysMenu].[MenuType],[SysMenu].[Remark],[SysMenu].[ShowMenu],[SysMenu].[SortNumber],[SysMenu].[OpenState],[SysMenu].[UpdateTime] FROM [SysMenu] INNER JOIN [SysRole2Menu] ON [SysRole2Menu].[SysMenuOID]=[SysMenu].[SysMenuOID] WHERE [SysRole2Menu].[SysRoleOID] IN(SELECT [SysUser2Role].[SysRoleOID] FROM [SysUser2Role] WHERE [SysUser2Role].[SysUserOID]=@P_fd6c25e426b6426280fdc1d619775e99 UNION SELECT [SysGroup2Role].[SysRoleOID] FROM [SysGroup2Role] INNER JOIN [SysGroup2User] ON [SysGroup2Role].[SysGroupOID]=[SysGroup2User].[SysGroupOID] WHERE [SysGroup2User].[SysUserOID]=@P_19337a08b9dc48baba73b88b83baceca) AND ([SysMenu].[ShowMenu]=@P_2295135526b54da5b7baba3051c65b7b OR [SysMenu].[ShowMenu] IS NULL)) AS [A] LEFT JOIN [SysUserMenuTemp] ON [A].[SysMenuOID]=[SysUserMenuTemp].[SysMenuOID] ORDER BY [SysUserMenuTemp].[SortNumber] ASC,[A].[SortNumber] ASC @P_43063492ed5a467ab0dddd9043a5e4c8: 2f1f7bb3-22ab-4478-a9e1-1090242f2276 @P_7183594707124d339902badd64347c30: 1 @P_fd6c25e426b6426280fdc1d619775e99: 2f1f7bb3-22ab-4478-a9e1-1090242f2276 @P_19337a08b9dc48baba73b88b83baceca: 2f1f7bb3-22ab-4478-a9e1-1090242f2276 @P_2295135526b54da5b7baba3051c65b7b: 1
以上都是查詢的,增刪該就相對簡單多了:
//Insert SysUser user = new SysUser(); user.SysUserOID = Guid.NewGuid(); user.LoginName = 'a'; db.IFrom<SysUser>().Execute(user); //Update SysUser user = new SysUser(); user.SysUserOID = Guid.NewGuid(); user.LoginName = 'a'; db.UFrom<SysUser>().Execute(user); //Delete db.DFrom<SysUser>().Where(SysUser.LoginName_.Like('%a%')).Execute();
以上列舉了一些用法,下面說一下代碼生成器,模版引擎用的是開源的 TextTemplate,生成代碼的模版可以按照自己需求來寫。
代碼生成其中也只實現了SqlServer和SQLite 的代碼生成。
大家可一下載試用下,有什麼建議或有什麼bug歡迎提出。
下載連接:http://pan.baidu.com/s/1bnlIxrh
ORM可以這麼理解:
一般的,我們把系統所需要的數據放在數據庫中。而顯示給用戶的頁面中使用的數據是通過讀取數據庫並進一步處理得到的。
而數據庫中的數據是結構的。
我們需要的.net編程中的數據時面向對象整合了的。
故:我們需要一種機制,可以把數據庫中的結構性的數據轉換為面向對象的數據。於是就出現了系統架構中常見的3層架構:
底層:DAL(Data Access Layer,數據訪問層)
中間:BLL (Bussiness Logic Layer,業務邏輯層)
頂層:UI層~
DAL中,我們使用實體類完成對數據庫表的封裝:
例如:我們構建一個文章管理系統。需要以下表
[Articles] [Categories] [Comments]
以[Articles]為例,包含的字段:
[ArticleID] [Title] [Content] [AddedBy] [AddedDate]
DAL層對應的實體類為[ArticleDetails]
包含以下屬性[ArticleID] [Title].......等5個屬性,以此對應表的5個字段。
對應DB中的3個表,我們有3個實體類。
創建類SqlArticlesProvider 來完成對DB的操作的封裝。
通常每個方法封裝一個存儲過程~
例如:GetArticles(int categoryID)方法中。
我們連接DB,調用SP,並將返回的DataReader封裝到實體類集合List<ArticleDetails>中。以用於傳輸給BLL層。
BLL層:
之中的類稱為域對象。有[Article] [Category] [Comment]
這裡的每個類就是我們傳統OOP中的類。
每個對象包含描述自己的屬性和可執行行為的方法。
UI層,直接調用BLL層的類以獲取數據,並通過數據綁定控件顯示的頁面等~
說的有點亂。。。光這麼著說確實不是特別充分。。
而且真正實踐編程起來,比這個復雜。。
三層架構之後的系統更易於維護。變更底層數據存儲,需要改動的地方非常少。
故,主要是用於大中型系統架構。
而且現在推出LINQ後,對編碼量也降低了。但是單獨學習LINQ,時間也不會少。
如果不要LINQ的話,還是有很多工具代碼可以幫助自動的構建一些類的~
object value這個你也可以設置為可空類型啊。Nullable<T>