zoukankan      html  css  js  c++  java
  • 利用反射拼接SQL查询条件字符串

    一、应用场景

    假设我们有一张数据表Student,并且有以下字段

       public class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Grade{ get; set; }
        }

    当我们在写数据访问层的时候,需要根据Id获取数据,那我们就很自然的写一个方法 GetStudentById(int Id);假設需求还需要根据Name来获取数据,我们也很自然的再写另一个方法GetStudentByName(string name);此时,项目中,还需要一个根据年纪来查询数据的方法,或者根据Name和Grade来查询数据的方法,我们也会新增一个数据访问层方法或者进行方法重载GetStudent(string name,int Grade);

           而在我们写的这些方法中,几乎99%的代码是相同的,唯一不同的仅仅是Sql语句后的where条件而已,所以,我今天就想,有没有一种方法,我传入一个Student对象,方法自己判断我需要查询哪些字段呢?当然有,那就是反射了,不过,事后我发现还是有一点点缺陷,文章末尾会说到!

    二、"撸"起袖子,打开Visual Studio

        Demo开始前,你需要具备一点点的反射基础:

    1、using System.Reflection;   绝大部分使用的方法在这个命名空间中,有兴趣的可以使用Reflector反编译研究下源码

    2、Type t = object.GetType(); 获取当前实例的类型描述信息,从而描述信息当中,我们就可以很容易知道当前实例有哪些方法、属性等等……

    3、 PropertyInfo[] infos = t.GetProperties(); 获取从当前实例得到的描述信息中得到相关的属性数组,也就是这里可以得到Id,Name,Grade;

    三、Demo思路

        数据访问层的查询方法,接受一个Student实例参数,在调用该方法前,我们在业务逻辑层中实例化一个Student对象,并根据查询条件对该实例的属性进行赋值,比如,我想根据Id等于1的学生信息,那就在实例化对象后,对Id进行赋值即可。

    具体思路:

    (1)利用反射,获取条件参数实例中的属性数组;

    (2)遍历该属性数组,对当前属性的值进行判断,如果为空,则不在查询条件中,如果不为空,则是业务逻辑层想要的查询条件;

    (3)接上步,如果不为空,则获取当前属性的名称、Value,进行条件的拼接,装载在集合中;

    (4)遍历完毕,对集合进行join拼接;

            private Student GetStudent(Student stu)
            {
                //获取当前实例的描述信息
                Type t = stu.GetType();
                //从描述信息当中,获取当前实例的属性数组
                PropertyInfo[] infos = t.GetProperties();
                //用于装载最终的查询条件的集合
                List<string> list = new List<string>();
                for (int i = 0; i < infos.Length; i++)
                {
                    //当前属性的值不为null,则证明是业务逻辑层中想要的查询条件
                    if (infos[i].GetValue(stu, null) != null)
                    {
                        string temp = string.Format("{0}='{1}'", infos[i].Name, infos[i].GetValue(stu, null));
                        list.Add(temp);
                    }
                }
                //拼接sql语句
                string s = string.Join("and", list);
                //todo:拼接SQL语句,进行数据库查询
                return null;
            }

    四、验证

    假如,我想要查询Id=1并且Name=dotnetgeek的条件的学生记录,那我们就要在调用数据访问层方法前,进行初始对象实例化,并且对属性进行赋值;

    Student s = new Student();
    s.Id = 1;
    s.Name = "dotnetgeek";
     //调用数据访问层方法
    GetStudent(s);
    

    则最终拼接出来的SQL条件则会是如图所示:(这里只演示到拼接SQL语句的步骤,进行数据查询不是本文章讨论范围)

    五、Bug

        不知道大家有没有发现到,查询条件里面出现了一个Bug,请留意我调用方法前是对Id,Name属性进行赋值的,最终SQL条件里又多了一个Grade属性,这里因为实体类中,Grade是int类型,是int类型的话就会默认值为0,所以,如果想用这种解决方法的话,还需在判断为null的地方再判断不能为0,but,如果用户想查询该字段等于0的记录怎么办?

    六、总结

       这个Demo是我在编码中浮想出来的,当时我已经写了2个功能相同的方法,加上同事已经写过1个相类似的方法,整个数据访问层中已经出现了相似的三个方法了,假如其他同事又有别的业务需求,是不是要再写第4个,第5个,第……个呢?所以我就想有没有一种方法可以实现一下,再说,在Entity Framework中,进行删除操作也是传入一个实体模型的,如果有兴趣的可以去研究下EF的源码!

    作者:dotnetgeek
    出处: http://www.cnblogs.com/waynechan
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    如果你觉得本文写得不错,请点击右下角的推荐按钮,如果觉得本文有所欠缺,请评论或联系我!

    如果你是广州、深圳、东莞三地的程序员,我欢迎你加入广深莞.NET技术交流群: 185718116

  • 相关阅读:
    IP fragmentation
    pci驱动
    cpu地址空间
    CentOS7 安装bazel
    kettle集群
    TextRankGloVe算法资料
    使用Kong Service负载均衡Load Balance功能
    自建ss服务器教程
    OpenSSL创建TLS/SSL证书
    监控告警
  • 原文地址:https://www.cnblogs.com/waynechan/p/3059570.html
Copyright © 2011-2022 走看看