WEB开发网
开发学院WEB开发ASP.NET ado.net快速上手疑问及解答(完结篇) 阅读

ado.net快速上手疑问及解答(完结篇)

 2010-05-26 17:48:26 来源:WEB开发网   
核心提示:楼猪上周周末偶而有感而发(也就是ado.net快速上手实践篇(一)和(二) ),想不到收到三位童鞋的邮件,ado.net快速上手疑问及解答(完结篇),提出了他们的疑问,并指出楼猪在源码中存在的问题,呵呵,真诚期待您的功德圆满那一天早日到来,非常感谢他们的细心和认真的态度,在这里抱住鸣谢一下

楼猪上周周末偶而有感而发(也就是ado.net快速上手实践篇(一)和(二) ),想不到收到三位童鞋的邮件,提出了他们的疑问,并指出楼猪在源码中存在的问题。非常感谢他们的细心和认真的态度,在这里抱住鸣谢一下。下面,楼猪就把童鞋们发现的问题和提出的疑问一并整理,统一回复一下,草草落笔,恐怕还有讹误,请注意甄别。
一、代码中的问题
1、伪SqlMapper的基类为什么用抽象类BaseSqlMapper而不用接口?
答:楼猪也知道在IBatis下的SqlMapper的基类就是一个接口ISqlMapper,但是楼猪写代码的时候,发现泛型约束在抽象基类里写一次,在SqlMapper下就不要再写了,而用接口就必须写两遍约束。呵呵,一时偷懒的后果,没有深刻意识到“针对接口编程”这一条常识,提出这个问题的童鞋明显可以看出技高楼猪一筹啊,,哈哈,楼猪吸取这个教训了,本文最后的demo楼猪将BaseSqlMapper统一换成了ISqlMapper接口,请留意。
2、在前台页面里面写SQL语句太多,是不是不太好?
这个问题也很好。在实际的项目中,SQL语句通常都写在具体的Dao文件中,比如前文demo中提到的PersonDao类。我们在添加一个Person的时候,示例中是通过view plaincopy to clipboardPRint?
public int Insert(string sqlInsert) 

public int Insert(string sqlInsert)
这种形式的方法执行插入的,但是在实际项目中的时候,我们通常都会写view plaincopy to clipboardprint?
public int Insert(Person model) 

public int Insert(Person model)
这种类型的方法执行数据库插入操作。所以在前台(表现层)写SQL语句其实是不合理的。再次多多感谢指出代码问题的童鞋们。如果已经对某些新手造成某些误导,楼猪在这里要深刻反省和检讨(demo写的明显有点随意和偷懒),在这里,楼猪郑重提醒,SQL语句的位置请不要模仿demo中这种糟糕的写法,楼猪也是过来人,因为使用Batis.net的时候都是放在Dal层xml下的,请务必重视起来。

二、疑问(直接摘录邮件内容)
1、“数据库切换貌似没有是吧.怎样切换MSSQL。ACC,XML等等呢”?
答:这个应该是说源码对多种数据库的支持问题。哦,楼猪还没有实现。看源码,Sql Server简单的基本的CRUD功能已经支持了。如果要扩展支持其他数据库,模仿SqlServer类里的具体实现即可。楼猪的机器环境上没有安装Oracle或者MySQL等数据库,所以写完了也不好测试。您如果条件具备,自己可以试着完成它。至于说数据库的切换,理想状态的实现莫过于最经典的抽象工厂模式,呵呵,配置文件配合反射就行了。但是楼猪建议您简单使用伪SqlMapper进行数据库类型切换。具体操作,其实只要在配置文件appsetting中加一个数据库类型节点sqlType,配合类里的常用数据库类型的枚举即可。

  <appSettings>
   <add key="db_timeOut" value="5000"/>
   <!--数据库类型 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
     }
}

然后,就是一些实例化SqlMapper的过程判断了,将数据库切换的问题完全转移到实例化SqlMapper上来:

代码
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;//数据库类型 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;
       }
       //实例化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 未实现
           break;
         case 2:
           //operation = new MySql(sqlConStr, connTimeOut);//MySql 也没有实现呢
           break;
       }
       if (operation == null)
       {
         throw new Exception("您配置的数据库类型有可能那啥出问题了");
       }
       SqlMapper mapper = new SqlMapper(operation);
       dictMappers.Add(connKey.ToUpper().Trim(), mapper);//不区分大小写
     }

   public static ISqlMapper GetMapper(string sqlConKey)
     {
       if (string.IsNullOrEmpty(sqlConKey))
       {
         throw new Exception("数据库连接字符串主键为空!");
       }
       sqlConKey = sqlConKey.ToUpper();//不区分大小写
       ISqlMapper mapper = null;
       if (dictMappers.ContainsKey(sqlConKey))
       {
         mapper = dictMappers[sqlConKey];
       }
       else
       {
         throw new Exception(string.Format("没有{0}所对应的数据库连接", 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

   }
}

必须要注意,这里的数据库切换方式不是绝对的,您可以按照自己喜欢的习惯的其他方式编程完成切换,楼猪这里只是抛砖而已。
2、“我对ORM不熟悉,想问下您的这个ORM到底是节省了哪部分工作? 我看里面有大量的反射,这样是不是非常影响效率?”
首先,楼猪对ORM也不太熟悉。现在实现的这个严格来说也根本谈不上算是ORM,但是有楼猪自己使用过的两个ORM的影子。
其次,当前实现的东东不是为了节省哪部分工作而设计的,楼猪的初衷是重读ado.net经典红皮书而做的复习笔记。
第三,反射相对于没有使用反射,当然非常影响效率。需要说明的是,要不要使用反射应该根据实际的项目需要。根据楼猪个人开发经验,对于大多数程序员要实现的简单的常见的前后台mis系统,在保证基本需求的情况下,客户如果对效率没有意见,用用没有太大关系,大部分工作就交给服务器完成去吧,程序员不用做太多工作。但是对于访问频繁的大型网站,实时系统或者应对大数据量操作的系统等等,建议不要使用反射,而且可能要重点花精力在数据“装潢”上面。
最后,如果有童鞋对ORM感兴趣,不妨在网上搜搜大牛们的作品,大名鼎鼎的NHibernate,iBatis.net,WebSharp,LINQ等等(这么多ORM,一个一个都要熟悉,源码也研究不过来啊,建议新手熟练一两种足矣),也许对您有更多的启发。如果您自己实现了类似其他流行ORM的主流功能(如自动生成SQL语句或者通过XML配置,缓存,延迟加载等等),并且功能更加强大,用起来更加顺手方便的新ORM,呵呵,真诚期待您的功德圆满那一天早日到来,快点来造福万千程序员吧。

稍作改进后的demo下载:demo

作者:Jeff Wong
出处:http://www.cnblogs.com/jeffwongishandsome/

Tags:ado net 快速

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接