用于搜索查询的 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)
{
}
}
问题中提供的代码是如何不编写代码的主要示例。
使用字符串连接创建 SQL 语句存在安全风险 - 因为它为 SQL 注入攻击敞开了大门。 在将用户输入传递到数据库时始终使用参数。
大部分代码都是重复的。事实上,switch 分支中唯一不同的是 SQL 语句。
在处理实现了 IDisposable
接口的 classes 实例时始终使用 using
语句 - 以及所有 ADO.Net classes 是 IDisposable
。这将确保您的实例得到处理。
在您的 case 语句中使用 "magic strings"。更好的解决方案是将指定的 class 与常量一起使用,而不是在整个代码中使用魔术字符串。
您的代码涉及 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 和它的答案。
这些代码工作正常,但我仍然想知道我是否需要使用 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)
{
}
}
问题中提供的代码是如何不编写代码的主要示例。
使用字符串连接创建 SQL 语句存在安全风险 - 因为它为 SQL 注入攻击敞开了大门。 在将用户输入传递到数据库时始终使用参数。
大部分代码都是重复的。事实上,switch 分支中唯一不同的是 SQL 语句。
在处理实现了
IDisposable
接口的 classes 实例时始终使用using
语句 - 以及所有 ADO.Net classes 是IDisposable
。这将确保您的实例得到处理。在您的 case 语句中使用 "magic strings"。更好的解决方案是将指定的 class 与常量一起使用,而不是在整个代码中使用魔术字符串。
您的代码涉及 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 和它的答案。