首页 > 代码库 > 重构之路 组合查询之传递SQL字符串

重构之路 组合查询之传递SQL字符串

         既然是使用VB.NET语言对机房收费系统进行重构,那么无可避免的要去解决组合查询的问题,在VB版的实现中这是一个难点,不过大家还是依靠自己或者共同的智慧解决了这个看似复杂的问题。

         如今编程的语言不同是一方面,更重要的是系统的结构不一样了,采用了三层架构去实现系统,这样一来就要考虑组合查询的在三层结构中的实现方法。当然,组合查询的核心办法是不变的,都是通过将查询的各个条件组装成SQL查询语句的where子句来实现的,问题就是这个where子句的组装在哪里完成?

         如果放在U层完成,那么我们向下传递的参数就是SQL语句的字符串了,如果放在D层完成,那么我们就要将U层输入的字段内容,操作符号和查询内容当做参数传到D层,然后在D层完成组装,最后调用SQLHelper中的函数执行SQL语句,将结果返回即可,就这么简单。下面我们先来看传SQL语句字符串的解决方案:

         首先是U层的代码,U层我们主要完成的是将用户输入的内容进行转换和拼接,形成字符串作为参数向下传递。因为用户输入的字段名称和逻辑关系符号都是汉字的形式,而SQL语句中都为英文形式,必须进行转换,考虑到很多窗体都要使用,因此将转换字段名称和逻辑关系符号封装为两个函数,放在U层的模块中,方便调用,具体实现如下:

         ModelUI的两个转换函数:

         

    ''' <summary>
    ''' 该函数的功能主要是将用户输入的汉字形式的字段名转换为英文形式的字段名称,即数据库中对应的字段名称
    ''' </summary>
    ''' <param name="str"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ConvertField(ByVal str As String) As String
        Dim result As String = ""
        Select Case (str)
            Case "卡号"
                result = "cardID"
            Case "学号"
                result = "studentID"
            Case "姓名"
                result = "studentName"
            Case "性别"
                result = "sex"
            Case "专业"
                result = "major"
            Case "班级"
                result = "classname"
            Case "上机日期"
                result = "onDate"
            Case "机器号"
                result = "computer"
            Case "下机日期"
                result = "offDate"
            Case "消费金额"
                result = "consume"
            Case "用户名"
                result = "userName"
            Case "登录日期"
                result = "loginDate"
            Case "注销日期"
                result = "logoutDate"

        End Select
        Return result

    End Function
    ''' <summary>
    ''' 该函数的主要功能是将用户输入的汉字形式的逻辑关系符号转为SQL语言中的英文形式
    ''' </summary>
    ''' <param name="str"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ConvertLogic(ByVal str As String) As String
        Dim result As String = ""
        Select Case (str)
            Case "或"
                result = " or "
            Case "与"
                result = " and "
        End Select
        Return result

    End Function

         U层窗体frmStudentInfo的btnQuery的单击事件代码:

         

 Private Sub btnQuery_Click(sender As Object, e As EventArgs) Handles btnQuery.Click
        btnModify.Enabled = True
        Dim mylist As New List(Of Entity.QueryBalanceEntity)
        Dim Bstudent As New BLL.StudentBLL
        Dim sqlstr As String = Nothing

        '拼接sql字符串,完成参数sqlstr的赋值操作
        If comboLogic1.Text.Trim = "" Then
            sqlstr = ConvertField(comboField1.Text.Trim) + comboOperator1.Text.Trim + "'" + txtContent1.Text.Trim + "'"
        Else
            sqlstr = ConvertField(comboField1.Text.Trim) + comboOperator1.Text.Trim + "'" + txtContent1.Text.Trim + "'" _
                + ConvertLogic(comboLogic1.Text.Trim) + ConvertField(comboField2.Text.Trim) + comboOperator2.Text.Trim + "'" + txtContent2.Text.Trim + "'"
            If comboLogic2.Text.Trim <> "" Then
                sqlstr = ConvertField(comboField1.Text.Trim) + comboOperator1.Text.Trim + "'" + txtContent1.Text.Trim + "'" _
                + ConvertLogic(comboLogic2.Text.Trim) + ConvertField(comboField2.Text.Trim) + comboOperator2.Text.Trim + "'" + txtContent2.Text.Trim + "'" _
                + ConvertLogic(comboLogic2.Text.Trim) + ConvertField(comboField3.Text.Trim) + comboOperator3.Text.Trim + "'"+ txtContent3.Text.Trim+"'"
            End If

        End If
        '使用B层的实例对象调用B层的函数完成查询
        mylist = Bstudent.QueryStudent(sqlstr)
        If mylist.Count > 0 Then
            DataGridView1.DataSource = mylist
        Else
            MsgBox("未检索到您需要的信息,请重新确认您输入的信息是否有误", MsgBoxStyle.OkOnly, "提示")
        End If



    End Sub

         B层相应的函数代码:

         

    Public Function QueryStudent(ByVal sqlstr As String) As List(Of Entity.QueryBalanceEntity)
        Dim istudent As IStudent
        Dim fstudent As New SQLServerFactory
        istudent = fstudent.CreateStudent
        Return istudent.QueryStudent(sqlstr)


    End Function

         D层相应的函数代码:

         

    Public Function QueryStudent(ByVal sqlstr As String) As List(Of Entity.QueryBalanceEntity) Implements IStudent.QueryStudent
        Dim studentHelper As New SQLHelper.SQLSeverHelper
        Dim mylist As New List(Of Entity.QueryBalanceEntity)
        Dim mydt As New DataTable
        Dim sql As String = "select * from  V_QueryBalance where " + sqlstr

        mydt = studentHelper.ExecuteSelect(sql, CommandType.Text)
        mylist = Entity.ConvertTo.ConvertToList(Of Entity.QueryBalanceEntity)(mydt)

        Return mylist

    End Function

         至于上述代码中用来执行SQL语句的ExecuteSelect函数和用来将DataTable转为List泛型集合的ConvertToList函数就不在这里赘述了,相信大家都有自己封装的函数,这里我们主要讨论如何在三层结构中实现组合查询的功能。

         最后总结一下这个解决方案,个人觉得这个方法特别简单,也很好理解,传递字符串的想法是我从高迎师姐的博客里看到的,并简化了代码,以自己的形式去重新书写了代码。但是这种方法有一个严重的缺陷,相信了解的人都知道,那就是SQL注入的问题,当然我们可以在输入框中限制用户的输入,从而防止SQl注入问题,但是这样相比较而言,安全性还是差一些,有没有更好的方法呢?