zoukankan      html  css  js  c++  java
  • ado.net快速上手疑问及解答(完结篇)

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

    public int Insert(string sqlInsert)

    这种形式的方法执行插入的,但是在实际项目中的时候,我们通常都会写

    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

  • 相关阅读:
    vue使用elementui合并table
    使用layui框架导出table表为excel
    vue使用elementui框架,导出table表格为excel格式
    前台传数据给后台的几种方式
    uni.app图片同比例缩放
    我的博客
    【C语言】取16进制的每一位
    SharePoint Solution 是如何部署的呢 ???
    无效的数据被用来用作更新列表项 Invalid data has been used to update the list item. The field you are trying to update may be read only.
    SharePoint 判断用户在文件夹上是否有权限的方法
  • 原文地址:https://www.cnblogs.com/jeffwongishandsome/p/1743854.html
Copyright © 2011-2022 走看看