這兩天看園子裏有個朋友寫Dapper的拓展,想到本身以前也嘗試用過,但不順手,曾寫過幾個方法來完成自動的Insert操做。而對於Update、Delete、Select等,我一直對Dictionary<string,object>參數類型有很深的感情,旨在頁面傳遞的條件基本上都是Json,很容易用字典類型存儲,想過在遵循某種命名規則的前提下,自動完成查詢,簡單的業務,直接能獲得相應條件的數據,爲此研究過一段時間,若是須要詳細的瞭解,請看這裏:html
看了下文章的時間,嚇我一條,竟然在2個月前,事實上,這個念頭在內心也一直有很長時間了,卻以爲本身很難去處理好它,封裝的沒問題,但用起來特別不順手。現在新年來臨,再來挑戰本身。緩存
以前遇到的最大的問題就是處理值與類型的映射。因爲頁面傳遞的是Json數據源,後來序列化成Dictionary<string,object>後,不少類型就丟失了。如直接引發程序錯誤的DateTime類型了。原來的處理方式是各類手動的映射,更改數據類型,再提交ado.net操做。app
現在查看Poto這個Orm的源代碼,它在實體增刪改的時候將類型緩存起來,並且還有該類型的屬性,在使用的時候,作過幾迴轉換,而我像發現新大陸似得,以爲這徹底能夠解決個人問題呀。因而照搬了它的緩存部分代碼,並結合Dapper實現了實體的增刪改查,固然查詢是經過Dictionary的傳參。ide
1.在Dapper的1219行代碼處有方法 GetCacheInfo,在其中增長IDictionary參數支持。修改後的方法爲:測試
private static CacheInfo GetCacheInfo(Identity identity) { CacheInfo info; if (!TryGetQueryCache(identity, out info)) { info = new CacheInfo(); if (identity.parametersType != null) { if (typeof(IDynamicParameters).IsAssignableFrom(identity.parametersType)) { info.ParamReader = (cmd, obj) => { (obj as IDynamicParameters).AddParameters(cmd, identity); }; } #if !CSHARP30 else if ( //支持傳遞Dictionary<K,V>爲參數 typeof(IDictionary).IsAssignableFrom(identity.parametersType) || typeof(IEnumerable<KeyValuePair<string, object>>).IsAssignableFrom(identity.parametersType) && typeof(System.Dynamic.IDynamicMetaObjectProvider).IsAssignableFrom(identity.parametersType) ) { info.ParamReader = (cmd, obj) => { IDynamicParameters mapped = new DynamicParameters(obj); mapped.AddParameters(cmd, identity); }; } #endif else { info.ParamReader = CreateParamInfoGenerator(identity, false); } } SetQueryCache(identity, info); } return info; }
2.在Poto中,增長了OrderAttribute,定義在實體上,指定自動生成的Select排序規則。ui
基於實體的增刪改,參數是object,則能夠根據對象獲取到它的類型、屬性,還有定義在類上的Attribute。很容易就能夠構造出 insert、update、delete。另外因爲Dapper支持一次SQL,在多個對象上執行,我對方法作了這樣的改進,以充分利用Dapper。解釋下,一次SQL,在多個對象上執行,如批量Insert,批量Update,批量Delete。SQL語句使用參數化,則是同一條,執行時參數來自於不一樣的對象而已。因此增刪改查,參數爲object時,還能夠傳遞List、數組等。spa
在Update和Delete方法中,我還但願經過條件來操做,運用到上面說的基於命名規則拼接SQL的方式,固然Select操做也不例外。主要實現代碼:.net
private readonly Regex reg = new Regex(@"^(?<tab>\w+\.)?(?<Pre>(PK|Begin|End|Like|UnLike|Null|In))?(?<Key>\w+)$"); private string CreateWhere(PocoData t, IDictionary<string, object> condition) { var sql = new StringBuilder(); //遍歷條件 foreach (var key in condition.Keys.ToArray()) { var match = reg.Match(key); //正則獲取到屬性對應的字段名 var pre = match.Groups["Pre"].Value;//獲取命名規則中的比較謂詞 var colName = match.Groups["Key"].Value;//獲取字段名稱 //if (string.IsNullOrEmpty(tableName)) // tableName = match.Groups["tab"].Value;//獲取字段表名限定 var paraName = string.Format("{0}{1}", pre, colName);//獲取該條件被分配的過程參數名 var value = condition[key]; //拼接Sql語句 sql.AppendFormat(" {0} AND", Builder(pre, colName, paraName, t.TableInfo.TableName, value));//拼接SQL條件 if (pre == "In") //In拼接沒有使用過程參數,直接拼接了,將參數從字典中移除 { condition.Remove(key); continue; } //若該字段值的類型爲字符串,檢測實體中的類型 if (value.GetType() == typeof(string)) { PocoColumn prop; if (!t.Columns.TryGetValue(colName, out prop)) throw new Exception(string.Format("can't find any property in object.propertyName:{0},object:{1}", key, t.TableInfo.TableName)); if (prop.PropertyInfo.PropertyType != typeof(string)) condition[key] = prop.ChangeType(value); } } if (sql.Length > 3) sql.Length -= 3; return sql.ToString(); }
說到這裏,有個小插曲,我發現當我在SQL和Oracle下測試成功後,我傳遞的Dictionary,並無指定參數符號,如@或者: 。最後執行的DbCommand對象使用的參數名固然也沒有,可竟然沒有出現任何問題。不知道該怎麼解釋。這裏Sql的庫使用的System.Data.SqlClient, net4.0 。而Oracle是使用的官方的,Oracle.ManagedDataAccess.dll ,net4.0。若是有朋友知道,還請告知一二。雖然我想偷懶,但這種突如其來的幸福,仍是警戒下。
最後在Update方法上增長參數,指定更新的列。
解釋下什麼是基於單表的Orm。單表操做,增刪改查,全部的方法都是在同一個表或者實體上。因爲目前我尚未看Dapper或者Poco在多表下是怎麼操做的,而暫時我又須要緊急的使用在項目中,由於我不想在寫增刪改查,簡單業務下linq式的查詢我也不想寫。好吧,我認可我有點魯莽,不穩定的東西就投入使用,可實踐就是檢驗真理的惟一標準啊。說到實踐,關於Poto這個Orm,我看其餘人的介紹,通過各類測試,當我用了,我只想說,這測試不仔細,Oracle下各類錯誤,連自動分頁都是錯的。
寫到這裏,發現具體的實現方式,已然不值一提。在寫以前,各類困難,寫以後,想要介紹它的時候,發現太簡單,沒什麼可說的。代碼中有一點註釋,想看的朋友若是看不明白能夠諮詢。
先貼下封裝後的調用方式。
var db = new DbHelp(Program.facotry, Program.connStr); //增///////////////////////////////////////////////////////////////////// var tabAdd = new tab1() { Name = "ggggg", Home = "jjjjjj" }; var row = db.Add(tabAdd); //批量增 var tabAddArrary = new tab1[] { new tab1() { Name = "批量增1", Home = "批量增1" }, new tab1() { Name = "批量增2", Home = "批量增2" }}; row = db.Add(tabAddArrary); //改////////////////////////////////////////////////////////////////////////// var tabUpdate = new tab1() { Name = "fffffff", Home = "fffffff", ID = 5 }; row = db.Update(tabUpdate); //批量改 var tabUpdateArrary = new tab1[] { new tab1() { Name = "批量改1", Home = "批量改1", ID=10 }, new tab1() { Name = "批量改2", Home = "批量改2", ID=11 }}; row = db.Update(tabUpdateArrary); //條件修改 //1 定義要修改的內容 var dic = new Dictionary<string, object>(); dic["Home"] = DateTime.Now.ToString() + ":修改了"; //定義條件 這裏使用了命名規則 var condtion = new Dictionary<string, object>(); condtion["InID"] = "1,3,5"; row = db.Update<tab1>(dic, condtion); //刪除/////////////////////////////////////////////////// var tabDelete = new tab1() { ID = 10 }; db.Remove(tabDelete); //條件刪除 var dicDelete = new Dictionary<string, object>(); dicDelete["BeginID"] = 50; row = db.Remove<tab1>(dicDelete); //查詢///////////////////////////////////////////////////// var dicQuery = new Dictionary<string, object>(); dicQuery["EndID"] = 50; var qtab1 = db.Query<tab1>(dicQuery); //分頁/////////////////////////////////////////////////////////// int count; var dicPage = new Dictionary<string, object>(); dicPage["BeginID"] = 50; dicPage["EndID"] = 10; var qtabPage = db.Query<tab1>(dicQuery, 3, 5, out count);
最後祝你們立刻有錢。