ado.net快速上手疑問(wèn)及解答

字號(hào):


    一、代碼中的問(wèn)題
    1、偽SqlMapper的基類為什么用抽象類BaseSqlMapper而不用接口?
    答:樓豬也知道在IBatis下的SqlMapper的基類就是一個(gè)接口ISqlMapper,但是樓豬寫代碼的時(shí)候,發(fā)現(xiàn)泛型約束在抽象基類里寫一次,在SqlMapper下就不要再寫了,而用接口就必須寫兩遍約束。呵呵,一時(shí)偷懶的后果,沒(méi)有深刻意識(shí)到“針對(duì)接口編程”這一條常識(shí),提出這個(gè)問(wèn)題的童鞋明顯可以看出技高樓豬一籌啊,,哈哈,樓豬吸取這個(gè)教訓(xùn)了,本文最后的demo樓豬將BaseSqlMapper統(tǒng)一換成了ISqlMapper接口,請(qǐng)留意。
    2、在前臺(tái)頁(yè)面里面寫SQL語(yǔ)句太多,是不是不太好?
    這個(gè)問(wèn)題也很好。在實(shí)際的項(xiàng)目中,SQL語(yǔ)句通常都寫在具體的Dao文件中,比如前文demo中提到的PersonDao類。我們?cè)谔砑右粋€(gè)Person的時(shí)候,示例中是通過(guò)view plaincopy to clipboardPRint?
    public int Insert(string sqlInsert)
    public int Insert(string sqlInsert)
    這種形式的方法執(zhí)行插入的,但是在實(shí)際項(xiàng)目中的時(shí)候,我們通常都會(huì)寫view plaincopy to clipboardprint?
    public int Insert(Person model)
    public int Insert(Person model)
    這種類型的方法執(zhí)行數(shù)據(jù)庫(kù)插入操作。所以在前臺(tái)(表現(xiàn)層)寫SQL語(yǔ)句其實(shí)是不合理的。再次多多感謝指出代碼問(wèn)題的童鞋們。如果已經(jīng)對(duì)某些新手造成某些誤導(dǎo),樓豬在這里要深刻反省和檢討(demo寫的明顯有點(diǎn)隨意和偷懶),在這里,樓豬鄭重提醒,SQL語(yǔ)句的位置請(qǐng)不要模仿demo中這種糟糕的寫法,樓豬也是過(guò)來(lái)人,因?yàn)槭褂肂atis.net的時(shí)候都是放在Dal層xml下的,請(qǐng)務(wù)必重視起來(lái)。
    二、疑問(wèn)(直接摘錄郵件內(nèi)容)
    1、“數(shù)據(jù)庫(kù)切換貌似沒(méi)有是吧.怎樣切換MSSQL。ACC,XML等等呢”?
    答:這個(gè)應(yīng)該是說(shuō)源碼對(duì)多種數(shù)據(jù)庫(kù)的支持問(wèn)題。哦,樓豬還沒(méi)有實(shí)現(xiàn)。看源碼,Sql Server簡(jiǎn)單的基本的CRUD功能已經(jīng)支持了。如果要擴(kuò)展支持其他數(shù)據(jù)庫(kù),模仿SqlServer類里的具體實(shí)現(xiàn)即可。樓豬的機(jī)器環(huán)境上沒(méi)有安裝Oracle或者M(jìn)ySQL等數(shù)據(jù)庫(kù),所以寫完了也不好測(cè)試。您如果條件具備,自己可以試著完成它。至于說(shuō)數(shù)據(jù)庫(kù)的切換,理想狀態(tài)的實(shí)現(xiàn)莫過(guò)于最經(jīng)典的抽象工廠模式,呵呵,配置文件配合反射就行了。但是樓豬建議您簡(jiǎn)單使用偽SqlMapper進(jìn)行數(shù)據(jù)庫(kù)類型切換。具體操作,其實(shí)只要在配置文件appsetting中加一個(gè)數(shù)據(jù)庫(kù)類型節(jié)點(diǎn)sqlType,配合類里的常用數(shù)據(jù)庫(kù)類型的枚舉即可。
    <appSettings>
    <add key="db_timeOut" value="5000"/>
    <!--數(shù)據(jù)庫(kù)類型 0 SqlServer 1 Orcale 2 MySql-->
    <add key="sqlType" value="0"/>
    </appSettings>
    枚舉如下:
    代碼
    namespace AdoNetDataaccess.Mapper
    {
    public enum SqlEnum
    {
    Default = 0,
    SQLServer = 0,
    Oracle = 1,
    MySql = 1
    }
    }
    然后,就是一些實(shí)例化SqlMapper的過(guò)程判斷了,將數(shù)據(jù)庫(kù)切換的問(wèn)題完全轉(zhuǎn)移到實(shí)例化SqlMapper上來(lái):
    代碼
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    namespace AdoNetDataAccess.Mapper
    {
    using AdoNetDataAccess.Core.Contract;
    using AdoNetDataAccess.Core.Implement;
    #region enum
    public enum SqlEnum
    {
    Default = 0,
    SQLServer = 0,
    Oracle = 1,
    MySql = 1
    }
    #endregion
    public sealed class MapperUtill
    {
    #region fields
    public static string currentSqlKey = "sqlConn";
    public static int cmdTimeOut = 15;
    private static int sqlType = 0;//數(shù)據(jù)庫(kù)類型 0 SqlServer 1 Orcale 2 MySql
    private static readonly object objSync = new object();
    private static readonly IDictionary<string, ISqlMapper> dictMappers = new Dictionary<string, ISqlMapper>();
    #endregion
    #region constructor and methods
    private MapperUtill()
    {
    }
    static MapperUtill()
    {
    try
    {
    cmdTimeOut = int.Parse(ConfigurationManager.AppSettings["db_timeOut"]);
    }
    catch
    {
    cmdTimeOut = 15;
    }
    try
    {
    sqlType = int.Parse(ConfigurationManager.AppSettings["sqlType"]);
    }
    catch (Exception ex)
    {
    throw ex;
    }
    //實(shí)例化SqlDbMapper
    for (int i = 0; i < ConfigurationManager.ConnectionStrings.Count; i++)
    {
    string key = ConfigurationManager.ConnectionStrings[i].Name;
    string value = ConfigurationManager.ConnectionStrings[i].ConnectionString;
    CreateMapper(key, value, cmdTimeOut);
    }
    }
    public static ISqlMapper GetSqlMapper(string key)
    {
    return MapperUtill.GetMapper(key);
    }
    public static ISqlMapper GetCurrentSqlMapper()
    {
    return MapperUtill.GetMapper(currentSqlKey);
    }
    public static void CreateMapper(string connKey, string sqlConStr, int connTimeOut)
    {
    IDbOperation operation = null;
    switch (sqlType)
    {
    default:
    case 0:
    operation = new SqlServer(sqlConStr, connTimeOut);
    break;
    case 1:
    //operation = new Orcale(sqlConStr, connTimeOut);//Orcale 未實(shí)現(xiàn)
    break;
    case 2:
    //operation = new MySql(sqlConStr, connTimeOut);//MySql 也沒(méi)有實(shí)現(xiàn)呢
    break;
    }
    if (operation == null)
    {
    throw new Exception("您配置的數(shù)據(jù)庫(kù)類型有可能那啥出問(wèn)題了");
    }
    SqlMapper mapper = new SqlMapper(operation);
    dictMappers.Add(connKey.ToUpper().Trim(), mapper);//不區(qū)分大小寫
    }
    public static ISqlMapper GetMapper(string sqlConKey)
    {
    if (string.IsNullOrEmpty(sqlConKey))
    {
    throw new Exception("數(shù)據(jù)庫(kù)連接字符串主鍵為空!");
    }
    sqlConKey = sqlConKey.ToUpper();//不區(qū)分大小寫
    ISqlMapper mapper = null;
    if (dictMappers.ContainsKey(sqlConKey))
    {
    mapper = dictMappers[sqlConKey];
    }
    else
    {
    throw new Exception(string.Format("沒(méi)有{0}所對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接", sqlConKey));
    }
    return mapper;
    }
    /// <summary>
    /// 釋放所有
    /// </summary>
    public void Release()
    {
    foreach (KeyValuePair<string, ISqlMapper> kv in dictMappers)
    {
    SqlMapper mapper = kv.Value as SqlMapper;
    if (mapper == null)
    {
    continue;
    }
    mapper.CurrentDbOperation.CloseConnection();
    }
    dictMappers.Clear();
    }
    #endregion
    }
    }
    必須要注意,這里的數(shù)據(jù)庫(kù)切換方式不是絕對(duì)的,您可以按照自己喜歡的習(xí)慣的其他方式編程完成切換,樓豬這里只是拋磚而已。
    2、“我對(duì)ORM不熟悉,想問(wèn)下您的這個(gè)ORM到底是節(jié)省了哪部分工作? 我看里面有大量的反射,這樣是不是非常影響效率?”
    首先,樓豬對(duì)ORM也不太熟悉?,F(xiàn)在實(shí)現(xiàn)的這個(gè)嚴(yán)格來(lái)說(shuō)也根本談不上算是ORM,但是有樓豬自己使用過(guò)的兩個(gè)ORM的影子。
    其次,當(dāng)前實(shí)現(xiàn)的東東不是為了節(jié)省哪部分工作而設(shè)計(jì)的,樓豬的初衷是重讀ado.net經(jīng)典紅皮書而做的復(fù)習(xí)筆記。
    第三,反射相對(duì)于沒(méi)有使用反射,當(dāng)然非常影響效率。需要說(shuō)明的是,要不要使用反射應(yīng)該根據(jù)實(shí)際的項(xiàng)目需要。根據(jù)樓豬個(gè)人開(kāi)發(fā)經(jīng)驗(yàn),對(duì)于大多數(shù)程序員要實(shí)現(xiàn)的簡(jiǎn)單的常見(jiàn)的前后臺(tái)mis系統(tǒng),在保證基本需求的情況下,客戶如果對(duì)效率沒(méi)有意見(jiàn),用用沒(méi)有太大關(guān)系,大部分工作就交給服務(wù)器完成去吧,程序員不用做太多工作。但是對(duì)于訪問(wèn)頻繁的大型網(wǎng)站,實(shí)時(shí)系統(tǒng)或者應(yīng)對(duì)大數(shù)據(jù)量操作的系統(tǒng)等等,建議不要使用反射,而且可能要重點(diǎn)花精力在數(shù)據(jù)“裝潢”上面。
    最后,如果有童鞋對(duì)ORM感興趣,不妨在網(wǎng)上搜搜大牛們的作品,大名鼎鼎的NHibernate,iBatis.net,WebSharp,LINQ等等(這么多ORM,一個(gè)一個(gè)都要熟悉,源碼也研究不過(guò)來(lái)啊,建議新手熟練一兩種足矣),也許對(duì)您有更多的啟發(fā)。如果您自己實(shí)現(xiàn)了類似其他流行ORM的主流功能(如自動(dòng)生成SQL語(yǔ)句或者通過(guò)XML配置,緩存,延遲加載等等),并且功能更加強(qiáng)大,用起來(lái)更加順手方便的新ORM,呵呵,真誠(chéng)期待您的功德圓滿那一天早日到來(lái),快點(diǎn)來(lái)造福萬(wàn)千程序員吧。