用于搜索查询的 try-catch 语句和数据库连接

try-catch statement and database connection for search query

这些代码工作正常,但我仍然想知道我是否需要使用 try-catch 语句打开-关闭连接搜索查询的数据库。

非常感谢您的建议。

SqlConnection cn = new SqlConnection("Data Source = localhost; Integrated Security = True; Database = myDB;");
SqlDataAdapter adp = new SqlDataAdapter();

private void LoadSearch()
        {            
            switch (cmbCategory.Text)
            {
                case "All":                    
                    adp.SelectCommand = new SqlCommand("SELECT * FROM tblCommunication WHERE LetterType LIKE '" + txSearch.Text.Trim() + "' OR LetterNumber LIKE '" + txSearch.Text.Trim() + "' OR LetterAmount LIKE '" + txSearch.Text.Trim() + "' OR LetterFrom LIKE '" + txSearch.Text.Trim() + "' OR LetterTo LIKE '" + txSearch.Text.Trim() + "' OR ReceivedBy LIKE '" + txSearch.Text.Trim() + "' OR Requisition LIKE '" + txSearch.Text.Trim() + "' OR LetterSubject LIKE '" + txSearch.Text.Trim() + "' OR LetterContent LIKE '" + txSearch.Text.Trim() + "' OR LetterRemarks LIKE '" + txSearch.Text.Trim() + "'", cn);
                    DataTable dtAll = new DataTable();
                    //cn.Open();
                    adp.Fill(dtAll);
                    dgCommunications.DataSource = dtAll;
                    //cn.Close();                    
                    break;

                case "Incoming Communications":
                    adp.SelectCommand = new SqlCommand("SELECT CommType = '" + cmbCategory.Text + "', LetterDate, LetterReceived, LetterType, LetterNumber, LetterAmount, LetterFrom, LetterTo, ReceivedBy, Requisition, LetterSubject, LetterContent, LetterRemarks FROM tblCommunication WHERE LetterType LIKE '" + txSearch.Text.Trim() + "' OR LetterNumber LIKE '" + txSearch.Text.Trim() + "' OR LetterAmount LIKE '" + txSearch.Text.Trim() + "' OR LetterFrom LIKE '" + txSearch.Text.Trim() + "' OR LetterTo LIKE '" + txSearch.Text.Trim() + "' OR ReceivedBy LIKE '" + txSearch.Text.Trim() + "' OR Requisition LIKE '" + txSearch.Text.Trim() + "' OR LetterSubject LIKE '" + txSearch.Text.Trim() + "' OR LetterContent LIKE '" + txSearch.Text.Trim() + "' OR LetterRemarks LIKE '" + txSearch.Text.Trim() + "'", cn);
                    DataTable dtInc = new DataTable();
                   // cn.Open();
                    adp.Fill(dtInc);
                    dgCommunications.DataSource = dtInc;
                    //cn.Close();
                    break;

                case "Inside Communications":
                    adp.SelectCommand = new SqlCommand("SELECT CommType = '" + cmbCategory.Text + "', LetterDate, LetterReceived, LetterType, LetterNumber, LetterAmount, LetterFrom, LetterTo, ReceivedBy, Requisition, LetterSubject, LetterContent, LetterRemarks FROM tblCommunication WHERE LetterType LIKE '" + txSearch.Text.Trim() + "' OR LetterNumber LIKE '" + txSearch.Text.Trim() + "' OR LetterAmount LIKE '" + txSearch.Text.Trim() + "' OR LetterFrom LIKE '" + txSearch.Text.Trim() + "' OR LetterTo LIKE '" + txSearch.Text.Trim() + "' OR ReceivedBy LIKE '" + txSearch.Text.Trim() + "' OR Requisition LIKE '" + txSearch.Text.Trim() + "' OR LetterSubject LIKE '" + txSearch.Text.Trim() + "' OR LetterContent LIKE '" + txSearch.Text.Trim() + "' OR LetterRemarks LIKE '" + txSearch.Text.Trim() + "'", cn); ;
                    DataTable dtIns = new DataTable();
                    //cn.Open();
                    adp.Fill(dtIns);
                    dgCommunications.DataSource = dtIns;
                    //cn.Close();
                    break;

                case "Outgoing Communications":
                    adp.SelectCommand = new SqlCommand("SELECT CommType = '" + cmbCategory.Text + "', LetterDate, LetterReceived, LetterType, LetterNumber, LetterAmount, LetterFrom, LetterTo, ReceivedBy, Requisition, LetterSubject, LetterContent, LetterRemarks FROM tblCommunication WHERE LetterType LIKE '" + txSearch.Text.Trim() + "' OR LetterNumber LIKE '" + txSearch.Text.Trim() + "' OR LetterAmount LIKE '" + txSearch.Text.Trim() + "' OR LetterFrom LIKE '" + txSearch.Text.Trim() + "' OR LetterTo LIKE '" + txSearch.Text.Trim() + "' OR ReceivedBy LIKE '" + txSearch.Text.Trim() + "' OR Requisition LIKE '" + txSearch.Text.Trim() + "' OR LetterSubject LIKE '" + txSearch.Text.Trim() + "' OR LetterContent LIKE '" + txSearch.Text.Trim() + "' OR LetterRemarks LIKE '" + txSearch.Text.Trim() + "'", cn); ;
                    DataTable dtOut = new DataTable();
                    //cn.Open();
                    adp.Fill(dtOut);
                    dgCommunications.DataSource = dtOut;
                   // cn.Close();
                    break;                
            }            
        }

最好的方法之一是使用语句

using (SqlConnection connection = new SqlConnection(conString))
{
    try
    {
        //your switch case statement
    }
    catch (InvalidOperationException)
    {

    }
    catch (SqlException)
    {

    }
}

一种方法,你可以为下面的所有情况编写一个 comman 方法,并在所有情况下调用此方法

public void Command(string query,string conString)
{
    SqlDataAdapter adp = new SqlDataAdapter();
    using (SqlConnection connection = new SqlConnection(conString))
    {

        try
        {
            adp.SelectCommand = new SqlCommand(query,connection);
            DataTable dtOut = new DataTable();
            adp.Fill(dtOut);
            dgCommunications.DataSource = dtOut;
        }
        catch (InvalidOperationException)
        {

        }
        catch (SqlException)
        {

        }
    }
}

或者可以这样使用

SqlDataAdapter adp = new SqlDataAdapter();
using (SqlConnection connection = new SqlConnection(conString))
{

    try
    {
        switch (cmbCategory.Text)
        {
            case "All":                    
                break;

        }
    }
    catch (InvalidOperationException)
    {

    }
    catch (SqlException)
    {

    }
}

问题中提供的代码是如何不编写代码的主要示例。

  1. 使用字符串连接创建 SQL 语句存在安全风险 - 因为它为 SQL 注入攻击敞开了大门。 在将用户输入传递到数据库时始终使用参数。

  2. 大部分代码都是重复的。事实上,switch 分支中唯一不同的是 SQL 语句。

  3. 在处理实现了 IDisposable 接口的 classes 实例时始终使用 using 语句 - 以及所有 ADO.Net classes 是 IDisposable。这将确保您的实例得到处理。

  4. 在您的 case 语句中使用 "magic strings"。更好的解决方案是将指定的 class 与常量一起使用,而不是在整个代码中使用魔术字符串。

  5. 您的代码涉及 UI 元素和数据库访问 - 这里没有关注点分离。

那么你应该写什么呢?

嗯,您应该使用某种 n 层架构设计模式 - MVC、MVP 和 MVVM 是 n 层的一些常见实现。

这太宽泛了,无法在 SO post 中进行完整解释,但基本上它的意思是您的代码应分为(至少)3 个不同的部分:数据访问层、业务层逻辑层和 UI(用户界面)层。

最简单的 3 层形式是有一个 class 用于数据访问,一个 class 用于每个 form/window 的 UI,还有一个 class 用于每个 form/window 的业务逻辑。

因此,对于数据访问,class 旨在与您的数据库进行通信。
这个 class 应该对 UI 一无所知,对业务逻辑一无所知。它只需要有用于 CRUD 的方法——创建、读取、更新和删除数据。

根据你上面的代码,你可以使用这样的东西:

class DAL
{
    private readonly string _connectionString;
    public DAL(string connectionString)
    {
        _connectionString = connectionString;
    }

    public DataTable SearchAll(string searchText)
    {
        var sql = "SELECT * FROM tblCommunication "+
                  "WHERE LetterType = @searchText "+
                  "OR LetterNumber = @searchText  "+
                  "OR LetterAmount = @searchText  "+
                  "OR LetterFrom  = @searchText  "+
                  "OR LetterTo  = @searchText  "+
                  "OR ReceivedBy  = @searchText  "+
                  "OR Requisition  = @searchText  "+
                  "OR LetterSubject  = @searchText  "+
                  "OR LetterContent  = @searchText  "+
                  "OR LetterRemarks  = @searchText";

        var parameter = new SqlParameter("@searchText", SqlDbType.VarChar);
        parameter.Value = searchText;
        return GetDataTable(sql, CommandType.Text, parameter);
    }

    public DataTable SearchIncomingCommunications(string caterogy, string searchText) 
    { 
        // implementation same as the example above
        throw new NotImplementedException();
    }

    public DataTable SearchInsideCommunications(string caterogy, string searchText)
    {
        // implementation same as the example above
        throw new NotImplementedException();
    }

    // add other methods as well

 private DataTable GetDataTable(string sql, CommandType commandType, params SqlParameter[] parameters)
    {
        var dt = new DataTable();
        using (var con = new SqlConnection(_connectionString))
        {
            using (var cmd = new SqlCommand(sql, con))
            {
                cmd.CommandType = commandType;
                foreach (var parameter in parameters)
                {
                    cmd.Parameters.Add(parameter);
                }
                using (var da = new SqlDataAdapter(cmd))
                {
                    da.Fill(dt);
                }
            }
        }
        return dt;
    }
}

然后,在您的业务逻辑 class 中,您根据从 UI 获得的输入来确定您的 switch 语句是什么数据 table 到 return. 最后,在 UI 中,您 link 将 DataTable 连接到您的 dgCommunications 数据源。

至于错误处理-嗯,这不属于数据访问层。它属于业务逻辑层——因为在数据访问层中您几乎无能为力。阅读 softwareengineering.stackexchange.com 上的 this question 了解更多详情。

我会进一步解释,但我怀疑我已经超出了单个 Stack Overflow 答案的范围。剩下的留给你去研究。一个好的起点是 This SO question 和它的答案。