以高效且可维护的方式访问基于行的数据






3.07/5 (15投票s)
2006 年 8 月 1 日
2分钟阅读

67013
在 C# (.NET) 中访问基于行的数据库数据的方法
引言
在一个完美的系统中,无需维护。一切从一开始就设计良好。存储过程从不更改其返回游标,数据始终具有正确的尺寸和类型。但是,在现实世界中,情况会发生变化。更重要的是,在现实世界中,您将与多个开发人员一起工作。再加上大量的企业和文化沟通障碍,您就会得到一段很快变得难以管理的代码。本文专门针对从数据集访问行中的字段以及出现的一些小问题。
问题所在
在 C# 中针对任何数据库访问基于行的数据库数据是一项相当简单的任务。
foreach(DataRow row in table.Rows){
customer = new Customer();
customer.ID = (Int32)row[0];
customer.FirstName = row[1].ToString();
customer.LastName = row[2].ToString();
}//end foreach
这既快速又简单。它也很常见,因为我经常看到它的实现。
在一个单一开发团队/小型项目中,这不会构成问题。但是,考虑一下更大的情况。您工作的财富 500 强企业集团刚刚决定数据库中的 MiddleName 是一个必填字段。DBA 添加了该字段并更改了存储过程,现在您的代码无法工作了。更糟糕的是,它没有失败。
一个解决方案
最后,电子邮件被分发,负责的团队立即发现了错误。新代码如下所示
foreach(DataRow row in table.Rows){
customer = new Customer();
customer.ID = (Int32)row["customerID"];
customer.FirstName = row["firstName"].ToString();
customer.LastName = row["lastName"].ToString();
}//end foreach
不幸的是,这慢了两个数量级!在大多数情况下,没有人会注意到。但在其他情况下,这将像一个 *(此处插入陈词滥调)* 一样突出。
另一种解决方案
在连续熬夜数周并重写存储过程以使用完全限定名称和调整逻辑位后,应用程序中仍然可以节省更多内容。回顾用于将 50,000 个客户加载到某些客户对象中的 for 循环,很明显还有另一种方法。
int customerIDIndex = table.Columns.IndexOf("customerID");
int customerFirstNameIndex = table.Columns.IndexOf("firstName");
int customerLastNameIndex = table.Columns.IndexOf("lastName");
foreach(DataRow row in table.Rows){
customer = new Customer();
customer.ID = (Int32)row[customerIDIndex];
customer.FirstName = row[customerFirstNameIndex].ToString();
customer.LastName = row[customerLastNameIndex].ToString();
}//end foreach
可能出现的问题
在任何足够大的情况下,代码都可能与数据库不同步。特别是现在许多公司都将 SOX 标准应用于最琐碎的数据。考虑到这一点,还有一个步骤可以提高此代码的可维护性。添加一些断言将使任何调试器都能立即访问所有问题的逻辑根源,而不是花费一个小时来破译“友好的”错误消息。
int customerIDIndex = table.Columns.IndexOf("customerID");
int customerFirstNameIndex = table.Columns.IndexOf("firstName");
int customerLastNameIndex = table.Columns.IndexOf("lastName");
System.Diagnostics.Debug.Assert(customerIDIndex > -1,
"Database out of sync");
System.Diagnostics.Debug.Assert(customerFirstNameIndex > -1,
"Database out of sync");
System.Diagnostics.Debug.Assert(customerLastNameIndex > -1,
"Database out of sync");
foreach(DataRow row in table.Rows){
customer = new Customer();
customer.ID = (Int32)row[customerIDIndex];
customer.FirstName = row[customerFirstNameIndex].ToString();
customer.LastName = row[customerLastNameIndex].ToString();
}//end foreach
结论
可能还有其他解决方案。依靠更好的错误处理甚至可以消除对断言的需求。但是,在编写可维护的代码时,您必须进行防御性编码。希望这篇小文章说明了一种防御性编程方法,该方法也保持了高效编码的概念。
作为一个小但相关的旁注,也可以执行以下操作
int customerIDIndex = table.Columns.IndexOf("customerID");
int customerFirstNameIndex = table.Columns.IndexOf("firstName");
int customerLastNameIndex = table.Columns.IndexOf("lastName");
foreach(DataRow row in table.Rows){
customer = new Customer();
if(customerIDIndex > -1)
customer.ID = (Int32)row[customerIDIndex];
if(customerFirstNameIndex > -1)
customer.FirstName = row[customerFirstNameIndex].ToString();
if(customerLastNameIndex > -1)
customer.LastName = row[customerLastNameIndex].ToString();
}//end foreach
但我不会推荐这样做,因为它只是掩盖了错误并创建了许多不必要的 if 语句。