数据访问层组件设计以及选型意识流 第三次封装(极致、极简而不简单)

首先,我们来分析SELECT 语法:

 

SELECT  [ ALL | DISTINCT ]  [ TOP nExpr [PERCENT ][ Alias. ] Select_Item 
    [ [AS ] Column_Name]  [ , [Alias. ] Select_Item  [ [AS ] Column_Name] ...] 
    FROM  [ FORCE ]  [ DatabaseName! ]  Table  [ [AS ] Local_Alias] 
    [  [INNER | LEFT [OUTER ]  |  RIGHT  [ OUTER ]  |  FULL  [ OUTER ]  JOIN DatabaseName!] 
       Table  [ [AS ] Local_Alias]  [ ON JoinCondition ... ]
       [ [INTO Destination ]  |  [ TO FILE FileName [ADDITIVE ]  |  TO PRINTER  [ PROMPT ]  |  TO SCREEN]] 
       [ PREFERENCE PreferenceName ]  [ NOCONSOLE ]  [ PLAIN ]  [ NOWAIT ]
       [ WHERE JoinCondition [AND JoinCondition ... ]  [ AND | OR FilterCondition [AND | OR FilterCondition ... ]]]
    [ GROUP BY GroupColumn [, GroupColumn ... ][ HAVING FilterCondition ]  [ UNION [ALL ] SELECTCommand] 
    [ ORDER BY Order_Item [ASC | DESC ]  [ , Order_Item [ASC | DESC ] ...]]

 

 根据以上的语法,我的分析:

 

Distinct 一定要支持
Skip、  Top 一定要支持
Percent 很少用,可以不支持

[ LEFT|RIGHT|FULL ]  JOIN  ON  坚决不支持,用IN查询替换,然后在内存中JOIN

WHERE 多个条件组合
要支持的条件有:  =>>=<<=<>INNOT  INIS  NULLIS  NOT  NULLLIKENOT  LIKE 共12种条件
先不支持  BETWEENEXISTSNOT EXSITS(都可用其他的条件替换)

Group 会影响结果集(配合各种聚合函数使用) -- -复杂,不实现,GROUP对表的扫描是和没GROUP一样的,只是影响网络传输而已
Having 多个条件组合 -- -复杂,不实现,只是影响网络传输而已

Order  By 支持,在分页的时候需要


 注意,我们不支持OR,只支持AND,以为,OR条件可以被UNION代替,而UNION应该在内存中进行,而不是在数据库!

 

 根据以上的分析,我写了以下的代码:

 

     public  enum WhereConditionType
    {
        Equal,
        NotEqual,
        Bigger,
        NotBigger,
        Smaller,
        NotSmaller,
        Like,
        NotLike
    }
     public  interface IWhereCondition { }
     public  abstract  class ConditionBase
    {
         public  object Column {  getset; }
    }
     public  abstract  class WhereConditionBase : ConditionBase, IWhereCondition
    {
         public WhereConditionType Type {  getset; }
         public  object ObjValue {  getset; }
    }
     public  abstract  class WhereInConditionBase : ConditionBase, IWhereCondition
    { 
         public  bool InOrNot {  getset; }
         public IEnumerable< object> ObjValueList {  getset; }
    }
     public  class WhereCondition<T> : WhereConditionBase
    {
         private T _value;
         public T Value
        {
             get {  return _value; }
             set
            {
                ObjValue = value;
                _value = value;
            }
        }
    }
     public  class WhereLikeCondition : WhereCondition< string>
    {
    }
     public  class WhereInCondition<T> : WhereInConditionBase
    {
         private IEnumerable<T> _valueList;
         public IEnumerable<T> ValueList
        {
             get {  return _valueList; }
             set
            {
                ObjValueList = value.Cast< object>();
                _valueList = value;
            }
        }
    }
     public  class WhereNullCondition : ConditionBase, IWhereCondition
    {
         public  bool NullOrNot {  getset; }
    }

     public  class OrderByCondition
    {
         public  object Column {  getset; }
         public  bool AscOrNot {  getset; }
    }

 

 以上实现WHERE条件和ORDER BY.

 

然后我们写了对应的扩展方法,以及两个委托:

 

     public  static  class SqlExtension
    {
         public  static IWhereCondition SqlEqual<T>( this  object column, T value)
        {
             return  new WhereCondition<T>()
            {
                Column = column,
                Value = value,
                Type = WhereConditionType.Equal
            };
        }
         public  static IWhereCondition SqlNotEqual<T>( this  object column, T value)
        {
             return  new WhereCondition<T>()
            {
                Column = column,
                Value = value,
                Type = WhereConditionType.NotEqual
            };
        }
         public  static IWhereCondition SqlBigger<T>( this  object column, T value)
        {
             return  new WhereCondition<T>()
            {
                Column = column,
                Value = value,
                Type = WhereConditionType.Bigger
            };
        }
         public  static IWhereCondition SqlNotBigger<T>( this  object column, T value)
        {
             return  new WhereCondition<T>()
            {
                Column = column,
                Value = value,
                Type = WhereConditionType.NotBigger
            };
        }
         public  static IWhereCondition SqlSmaller<T>( this  object column, T value)
        {
             return  new WhereCondition<T>()
            {
                Column = column,
                Value = value,
                Type = WhereConditionType.Smaller
            };
        }
         public  static IWhereCondition SqlNotSmaller<T>( this  object column, T value)
        {
             return  new WhereCondition<T>()
            {
                Column = column,
                Value = value,
                Type = WhereConditionType.NotSmaller
            };
        }
         public  static IWhereCondition SqlLike( this  object column,  string value)
        {
             return  new WhereLikeCondition
            {
                Column = column,
                Value = value,
                Type = WhereConditionType.Like
            };
        }
         public  static IWhereCondition SqlNotLike( this  object column,  string value)
        {
             return  new WhereLikeCondition
            {
                Column = column,
                Value = value,
                Type = WhereConditionType.NotLike
            };
        }

         public  static IWhereCondition SqlIn<T>( this  object column, IEnumerable<T> valueList)
        {
             return  new WhereInCondition<T>
            {
                Column = column,
                ValueList = valueList,
                InOrNot =  true
            };
        }
         public  static IWhereCondition SqlNotIn<T>( this  object column, IEnumerable<T> valueList)
        {
             return  new WhereInCondition<T>
            {
                Column = column,
                ValueList = valueList,
                InOrNot =  false
            };
        }

         public  static IWhereCondition SqlNull( this  object column)
        {
             return  new WhereNullCondition
            {
                Column = column,
                NullOrNot =  true
            };
        }
         public  static IWhereCondition SqlNotNull( this  object column)
        {
             return  new WhereNullCondition
            {
                Column = column,
                NullOrNot =  false
            };
        }

         public  static OrderByCondition SqlOrderBy( this  object column)
        {
             return  new OrderByCondition
            {
                Column = column,
                AscOrNot =  true
            };
        }
         public  static OrderByCondition SqlOrderByDesc( this  object column)
        {
             return  new OrderByCondition
            {
                Column = column,
                AscOrNot =  false
            };
        }
    }

     public  delegate IWhereCondition WhereDelegate<TK>(TK p);
     public  delegate OrderByCondition OrderByDelegate<TK>(TK p);

 

 好吧,现在让我们一个类解决问题吧:

 

public  class LinqDAC<T> : DACBase<T>, IEnumerable<T>  where T :  classnew()
    {
         private  bool _isDistinct;
         private  int _skipNum = - 1;
         private  int _tackNum = - 1;
         private  string _cmdAlians;

         private IList<IWhereCondition> _whereConditions =  new List<IWhereCondition>();
         private IList<OrderByCondition> _orderByConditions =  new List<OrderByCondition>();
        
         public LinqDAC<T> SqlDistinct()
        {
            _isDistinct =  true;
             return  this;
        }
         public LinqDAC<T> SqlSkip( int skipNum)
        {
            _skipNum = skipNum;
             return  this;
        }
         public LinqDAC<T> SqlTack( int tackNum)
        {
            _tackNum = tackNum;
             return  this;
        }
         public LinqDAC<T> SqlSelect( string cmdAlians)
        {
            _cmdAlians = cmdAlians;
             return  this;
        }

         public LinqDAC<T> SqlWhere(Expression<WhereDelegate<T>> whereDelegate)
        {
             var expStr = whereDelegate.Body.ToString();
            

            var whereCondition = whereDelegate.Compile()( new T());
             var conditionBase = whereCondition  as ConditionBase;
             var dotIndex = expStr.IndexOf( ' . ');
             var endIndex = expStr.IndexOf( ' . ', dotIndex +  1);
             var endIndex2 = expStr.IndexOf( ' ) ');
            endIndex = endIndex < endIndex2 ? endIndex : endIndex2;

             if (conditionBase !=  null) conditionBase.Column = expStr.Substring(dotIndex +  1, endIndex - dotIndex -  1);

            _whereConditions.Add(whereCondition);
             return  this;
        }

         public LinqDAC<T> SqlOrderBy(Expression<OrderByDelegate<T>> orderByDelegate)
        {
             var expStr = orderByDelegate.Body.ToString();

             var dotIndex = expStr.IndexOf( ' . ');
             var endIndex = expStr.IndexOf( ' . ', dotIndex +  1);
             var endIndex2 = expStr.IndexOf( ' ) ');
            endIndex = endIndex < endIndex2 ? endIndex : endIndex2;


             var orderByCondition = orderByDelegate.Compile()( new T());
             if (orderByCondition !=  null) orderByCondition.Column = expStr.Substring(dotIndex +  1, endIndex - dotIndex -  1);

            _orderByConditions.Add(orderByCondition);
             return  this;
        }

         public IEnumerator<T> GetEnumerator()
        {
             // 得到语句并且查询
             return ToList().GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
             return GetEnumerator();
        }

         public IList<T> ToList()
        {
             string providerAlians = DataBaseInstance.ProviderAlians;
             string connAlians = DataBaseInstance.ConnAlians;
            AdoHelper ado = AdoHelper.CreateHelper(providerAlians);
             string conStr = DbConnectionStore.TheInstance.GetConnection(connAlians);
             if ( string.IsNullOrEmpty(_cmdAlians))
                _cmdAlians =  " Select " +  typeof(T).Name;
             var com = AdoHelper.GetCommandInfo(connAlians, _cmdAlians);
             var comtext = com.RealCommandText( typeof (T), ado, _whereConditions, _orderByConditions, _isDistinct, _skipNum, _tackNum);
            List<IDataParameter> outP;

             return ado.QuerySqlForList<T,  string, T>(conStr, comtext,  nullnullout outP,
                                connAlians, _cmdAlians);
        }

         public  void SqlDelete( string cmdAlians =  null)
        {
            _cmdAlians = cmdAlians;
             string providerAlians = DataBaseInstance.ProviderAlians;
             string connAlians = DataBaseInstance.ConnAlians;
            AdoHelper ado = AdoHelper.CreateHelper(providerAlians);
             string conStr = DbConnectionStore.TheInstance.GetConnection(connAlians);
             if ( string.IsNullOrEmpty(_cmdAlians))
                _cmdAlians =  " Delete " +  typeof(T).Name;
             var com = AdoHelper.GetCommandInfo(connAlians, _cmdAlians);
             var comtext = com.RealCommandText( typeof(T), ado, _whereConditions, _orderByConditions);
            List<IDataParameter> outP;

            ado.ExecuteNonQuery(conStr, comtext,  null, CommandType.Text,  out outP,
                                connAlians, _cmdAlians);
        }
         public  void SqlUpdate( string cmdAlians =  null)
        {
            _cmdAlians = cmdAlians;
             string providerAlians = DataBaseInstance.ProviderAlians;
             string connAlians = DataBaseInstance.ConnAlians;
            AdoHelper ado = AdoHelper.CreateHelper(providerAlians);
             string conStr = DbConnectionStore.TheInstance.GetConnection(connAlians);
             if ( string.IsNullOrEmpty(_cmdAlians))
                _cmdAlians =  " Update " +  typeof(T).Name;
             var com = AdoHelper.GetCommandInfo(connAlians, _cmdAlians);
             var comtext = com.RealCommandText( typeof(T), ado, _whereConditions, _orderByConditions);
            List<IDataParameter> outP;

            ado.ExecuteNonQuery(conStr, comtext,  null, CommandType.Text,  out outP,
                                connAlians, _cmdAlians);
        }

         public  void Clear()
        {
            _whereConditions =  new List<IWhereCondition>();
            _orderByConditions =  new List<OrderByCondition>();
            _isDistinct =  false;
            _skipNum = - 1;
            _tackNum = - 1;
            _cmdAlians =  null;
        }
    }

 

 

 

 注意到了么?我们继承了之前的DACBase<T>类, 还实现了IEnumerable<T>接口。支持延迟查询哦!

 

 

SqlDistinct 是否要Distinct

SqlSkip 跳过多少记录

SqlTack 返回多少记录

SqlSkip + SqlTack 完美支持分页哦

SqlSelect 指定一个命令执行,默认的是Select + T的类型名

SqlWhere 加上各种Where 条件(支持12种条件)

SqlOrderBy 加上排序,支持倒序

GetEnumerator 返回迭代器,支持延迟查询

ToList 立即查询

SqlDelete 执行删除

SqlUpdate 执行更新

Clear 把类置于初始状态,已执行下一个命令
 

 

 

本组件的缺点,很明显,在上面的分析部分已经讲明白了,不支持的就是不支持,我不打算去做数据库关系的MAPPING。

 

但是你说这个东西不能用,DAAB都能做的事它都能做,并且比DAAB好多了吧。

 

那么,我们看看它的使用方式吧:

 

            var dac = DependencyResolver.UnityDependencyResolver.Resolve<LinqDAC<ShopInfo>>();

            var retList = new List<ShopInfo>();

            var list = dac.SqlWhere(p => p.ShopID.SqlEqual(context.InnerRequest))
                //.SqlDistinct().SqlTack(1).SqlSkip(0)
                .ToList()

 

 

 和EF差不多吧。

 

 具体使用指南将在专门的使用指南里介绍,稍后我将上传全部源码。

 

回过都来,我们来看看它的短板的替代方案:

 

第一,JOIN 查询不支持, 没关系,前面以前说了,用IN查询来限定第二个结果集的大小,然后在内存里对两个结果集进行JOIN

 

第二,Group BY, 直接使用内存里的Group BY。

 

 

来看看丰富的集合操作的扩展方法吧:

 数据访问层组件设计以及选型意识流 第三次封装(极致、极简而不简单)_第1张图片

 对以上扩展方法的分析:

 

 

Aggregate 聚合函数
Aggregate 加上闭包传进列表长度能得到平均值
Aggregate 在RROUP  BY 中特别好用

ANYALL 返回BOOL
CONTAINS 指定一个比较器, 默认的构造器模板,传进一个委托返回BOOL 与ANY用法有相同之处

Avg只能返回一个DECIMAL,用 Aggregate 更好 
SUM
COUNT可带条件, 用 Aggregate 可实现
LongCount
MIN/MAX


CANCAT 不带条件
Distinct 带比较器
UNION 带比较器  = CANCAT  +  Distinct 
Except 带比较器


DefaultOrEmpty在实现LEFT Join的时候好用啊!!!
First带条件
FirstORDefault可实现DefaultIFEmpty,但更强大
Last
LastOrDefault
Single 不止一个就报错
SingleOrDefault
ElementAt
ElementAtDefault

ToDictnary
ToLookUp
ToArray
ToList

WHERE
Tack
TackWhile 和WHERE一样
Skip
SkipWhile

CAST
OfType
很有用,当然也能用WHERE  + CAST实现。
Reverse
SequenceEqual
在自动化测试中很好用,带比较器

ORDERBY 正序和倒序
GROUPBY
GROUPJOIN
JOIN
,条件为TRUE可实现笛卡尔乘积
INTERSECT 取交集

SELECT
SELECTMANY  可实现LEFT  JOIN,笛卡尔乘积, LEFT  JOIN 和  RIGHT  join 加起来UNION就是  FULL  JOIN

 

 可见,集合操作的扩展方法是极其丰富的,没有问题。

 

好,接下来的问题是,用IN 查询实现 限定JOIN查询的 第二个记录集的大小有没有性能问题。

我们知道一个in后面只能有1000个值

 

如果我们JION两张表,一张是15万的数据,另一张是2亿的数据

我们就要用150次IN查询 ,并且把结果UNION起来,好在我已经给你做了,你不需要写一个 for(var i=0, i <150, i++){}

 

现在只是需要确认一下性能和原本的JOIN查询差距有多大~~

 

一会出性能测试报告,敬请期待 。

 

PS: 测试结果出来的, IN查询的效率肯定是比JOIN 低的。究竟低多少呢?

 

6.2万 join 2亿, JOIN是0.015秒,

IN查询是0.46秒,

 

大数据量,差的比较多了,不过,小数据量就完全没区别了。

 

大数据量的情况下,查询结果其实都没有返回的,网络不行啊!

 

 

 

 上面的黄色高亮是本组件的短板,也就是缺点了~~

 

好了,终于写完了,算是对自己大约一个星期工作量的总结,写完了就对得起自己的熬夜了,也对得起公司,对得起大家了。

我真TM是个偏执的人!哈哈

 

 

 

PS, 上一篇中我可能犯了两个错误,以个人感受概全了大家的感受,以偏概全了:

一,也许我错了,让销售录入信息可能是只有我这样的懒销售才感到头痛,大部分销售是不会头痛的,他们可以一边谈客户一边录入,可以在家打开笔记本录入~~

二,也许我又错了,一个系统里应该可以存在两个以及以上的数据访问组件,然后优势互补

 

本系列四篇博文,只是做自己的工作总结,和发表自己的个人看法~不带其他感情色彩哦~~读者,切记切记

 

 

你可能感兴趣的:(设计)