c#与数据库代码简化
本文关键字:代码 数据库 | 更新日期: 2023-09-27 18:13:25
我正在做一个以Oracle数据库为中心的项目(尽管老实说我不认为这有什么关系),我发现自己有相当数量的重复代码,特别是异常。到目前为止,我看到的最好的方法是这个问题https://stackoverflow.com/a/1554/865868,它建议使用委托。这看起来像是一个完美的解决方案,直到我尝试在我的项目中实现它。我发现有一种情况是不实用的。
让我稍微描述一下我的程序。我有两段代码处理数据库操作。我的想法是调用一个返回数据表的函数,称为LoadDataTable()。然后有一个函数处理将列表中的项插入到表中。
private void AddToList(List<string> itemList) {
try {
using (OracleConnection connection = new OracleConnection(connectionString)) {
connection.Open();
foreach (string item in itemList) {
using (OracleCommand command = new OracleCommand()) {
command.Connection = connection;
//Insert operation here
//......
command.ExecuteNonQuery();
}
}
} catch (OracleException ex) {
string messageboxtitle = "Database Exception";
switch (ex.Number) {
case 00001:
MessageBox.Show("Constraint Violation Error", messageboxtitle, MessageBoxButtons.OK);
break;
case 12154:
MessageBox.Show(string.Format("Connection Error: {0}", ex.Message), messageboxtitle);
break;
default:
MessageBox.Show(ex.ToString());
break;
}
}
}
private DataTable LoadDataTable() {
DataTable dataTable = new DataTable();
try {
using (OracleConnection connection = new OracleConnection(connectionString)) {
connection.Open();
using (OracleCommand command = new OracleCommand()) {
command.Connection = connection;
command.CommandText = sql;
command.CommandType = CommandType.Text;
using (OracleDataAdapter oda = new OracleDataAdapter(command)) {
oda.Fill(dataTable);
}
}
}
} catch (OracleException ex) {
string messageboxtitle = "Database Exception";
switch (ex.Number) {
case 12154:
MessageBox.Show(string.Format("Connection Error: {0}", ex.Message), messageboxtitle); //Duplicate Exception
break;
default:
MessageBox.Show(ex.ToString());
break;
}
}
return dataTable;
}
请记住,我必须重写和简化代码,以便我可以讨论它。无论如何,看委托的例子,我很快意识到参数是一个问题。您不能为List<string>
类型使用参数,但是委派的有用性是毫无疑问的,因为我可以为不重复的异常设置一个集中的部分。
private delegate void DatabaseOperation(List<string> itemList);
private void PerformDatabaseOperation(DatabaseOperation operation, List<string> itemList){
try {
operation(itemList);
} catch (OracleException ex) {
string messageboxtitle = "Database Exception";
switch (ex.Number) {
case 00001:
MessageBox.Show("Constraint Violation Error", messageboxtitle, MessageBoxButtons.OK);
break;
case 12154:
MessageBox.Show(string.Format("Connection Error: {0}", ex.Message), messageboxtitle);
break;
default:
MessageBox.Show(ex.ToString());
break;
}
}
}
private void AddToList(List<string> itemList) {
using (OracleConnection connection = new OracleConnection(connectionString)) {
connection.Open();
foreach (string item in itemList) {
using (OracleCommand command = new OracleCommand()) {
command.Connection = connection;
//Insert operation here
//......
command.ExecuteNonQuery();
}
}
}
如何使用:
List<string> itemList = new List<string>();
//code to fill list
PerformDatabaseOperation(AddToList, itemList);
问题是现在我无法实现LoadDataTable()与这个委托,因为它没有任何参数。在委托上使用params
不能工作,因为List不兼容。我正在寻找改进我的代码技术,以提高可重用性和可读性,但我发现自己在旋转轮子阅读关于这个主题的各种线程,主要是因为它们没有深入到一个简单的例子,没有真正抓住我现在发现的问题。为了确保这个问题得到回答,让我提出最后一个问题。我怎样才能编写出避免重复异常的代码?
对于任何想要解决类似问题的人,请参阅下文。请记住,要改进代码还有很多工作要做。另外,任何对这里讨论的var
关键字感兴趣的人,请访问这里。我希望这对你有帮助:
private delegate void DatabaseOperation();
private void PerformDatabaseOperation(DatabaseOperation operation) {
try {
operation();
} catch (OracleException ex) {
string messageboxtitle = "Database Exception";
switch (ex.Number) {
case 00001:
MessageBox.Show("Constraint Violation Error", messageboxtitle, MessageBoxButtons.OK);
break;
case 12154:
MessageBox.Show(string.Format("Connection Error: {0}", ex.Message), messageboxtitle);
break;
default:
MessageBox.Show(ex.ToString());
break;
}
}
}
private void AddToList(List<string> itemList) {
using (OracleConnection connection = new OracleConnection(connectionString)) {
connection.Open();
foreach (string item in itemList) {
using (OracleCommand command = new OracleCommand()) {
command.Connection = connection;
//Insert operation here
//......
command.ExecuteNonQuery();
}
}
}
private DataTable LoadDataTable() {
DataTable dataTable = new DataTable();
using (OracleConnection connection = new OracleConnection(connectionString)) {
connection.Open();
using (OracleCommand command = new OracleCommand()) {
command.Connection = connection;
command.CommandText = sql;
command.CommandType = CommandType.Text;
using (OracleDataAdapter oda = new OracleDataAdapter(command)) {
oda.Fill(dataTable);
}
}
}
return dataTable;
}
请记住,委托从父方法的主体中捕获变量。这也被称为闭包。因此,委托通常不需要有参数列表。
var itemList = new List<string>();
PerformDatabaseOperation(
() => {
...
itemList.Add(...);
...
}
);
你可以这样调用它:
List<string> itemList = new List<string>();
PerformDatabaseOperation(() => AddToList(itemList));
技巧是将lambda表达式传递给没有参数的PerformDatabaseOperation
(空括号()
);PerformDatabaseOperation
也有没有 itemList
参数。lambda表达式的主体使用在调用PerformDatabaseOperation
之前声明和初始化的itemList
。c#编译器会完成剩下的工作。
我建议您使用具有Oracle支持的微型ORM,例如PetaPoco。如果代码可以自动生成,为什么还要写这些代码呢?如果您想编写自己的数据访问层,我建议您为您的类创建CRUD方法,例如
public bool Insert(Person p)
{...}
您也可以考虑使用泛型方法来完成此操作,例如:
public bool Insert<T>(T item)
{...}
传递可变形参的一种常用模式是将它们传递给构造函数。优点是构造函数不是接口的一部分。但是,它要求您使用对象而不是委托。
public interface IDatabaseOperation
{
void Execute();
}
public class LoadListDatabaseOperation : IDatabaseOperation
{
private List<string> _itemList;
public LoadListDatabaseOperation(List<string> itemList)
{
_itemList = itemList;
}
public void Execute()
{
...
// Fill the list here
...
}
}
传递对象的代价要高一些,但也有一些优点,比如可以创建具有不同程度专门化的操作的层次结构。您可能拥有泛型基操作和针对特定类型的派生操作。您还可以使用属性标量返回值等