0

我是一个数据库/SQL/ADO.NET 新手,在尝试学习诸如 NHibernate 或实体框架之类的 ORM 框架之前,我正在尝试建立一个坚实的基础。我一直在阅读与平台无关的 RDBMS 概念,现在我正在尝试将其调整为编写与数据库实际交互的干净且可重用的 C# 代码。我听说过 Martin Fowler 的企业应用程序架构模式,之前在这里推荐过,但是标题中的“企业”让我想知道在我准备好阅读那本书之前是否需要做一些中间学习步骤.

作为实践,我正在制作一个简单的 ASP.NET 网站,帮助访问者从有几千条记录的数据库中查找某些信息。这是一个非常简单的第一个项目——没有任何类型的用户帐户或登录名,并且该网站每天会获得大约十几个点击量。

我的 ASP.NET 代码具有一些类似这样的方法来从数据库中检索数据:

string dbConnectString = "...";

public List<string> GetItems()
   {
   List<string> rList = null;

   using (SqlConnection myConn = new SqlConnection(dbConnectString))
      {
      string queryStatement = "SELECT Name FROM SomeTable";

      using (SqlCommand myCmd = new SqlCommand(queryStatement, myConn))
         {
         DataTable resultTable = new DataTable("Results");
         using (SqlDataAdapter myAdapter = new SqlDataAdapter(myCmd))
            {
            myConn.Open();
            if (myAdapter.Fill(resultTable) > 0)
               {
               // This loop should probably be a LINQ expression
               rList = new List<string>();
               foreach (DataRow row in resultTable.Rows)
                  {
                  rList.Add((string)row["Name"]);
                  }
               }

            myConn.Close();
            }
         }
      }

   return rList;
   }

我认为就处理实现 IDisposable 的对象而言,我做了正确的事情。但是有没有更好的方法来编写方法本身?

以下是我的一些问题:

  1. 从我读过的内容来看,连接池似乎可以通过每次调用 GetItems() 等方法来实例化一个新的 SqlConnection 。是否有一种“更干净”的方式来编写代码,所以我仍然会进行适当的资源管理,但不会像这样的块中有太多重复using (SqlConnection ...)?这种方法怎么样:

    public class DatabaseManager : IDisposable
       {
       protected SqlConnection myConn;
    
       public DatabaseManager(string connectionString)
          {
          // Set up the constructor
          myConn = new SqlConnection(dbConnectString);
          }
    
       // IDisposable implementation stuff goes here.  Any usage of 
       // DatabaseManager would have to take place in a using() block.
    
       public List<string> GetItems()
          {
          List<string> rList = null;
    
          string queryStatement = "SELECT Name FROM dbo.SomeTable";
    
          using (SqlCommand myCmd = new SqlCommand(queryStatement, myConn))
             {
             DataTable resultTable = new DataTable("Results");
             using (SqlDataAdapter myAdapter = new SqlDataAdapter(myCmd))
                {
                myConn.Open();
                if (myAdapter.Fill(resultTable) > 0)
                   {
                   rList = new List<string>();
                   foreach (DataRow row in resultTable.Rows)
                      {
                      rList.Add((string)row["Name"]);
                      }
                   }
    
                myConn.Close();
                }
             }
    
          return rList;
          }
       }
    
  2. 除了我无耻地使用垂直间距之外,还有更优雅的方法可以从数据库查询的结果中提取列表吗?一种方法是用 LINQ 调用替换 foreach() 迭代,但这只会节省两三行代码。

多谢你们!

4

1 回答 1

3

您的代码既不干净也不可重用:

  1. sql 查询和列名被硬编码到管理器类中,这使得每个表都需要一个额外的管理器。您可以通过允许注入实际查询来解决此问题,但最终您将得到一个具有不同职责的“经理经理”
  2. sql 连接的生命周期与管理器的生命周期相关联,这使得无法通过复合数据库访问进行事务
  3. 没有错误处理
  4. 使用数据适配器首先检索数据,然后将其复制到列表中不如使用数据读取器有效

要解决所有这些问题,您需要大量时间和很多聪明的想法。您在使用单个选择查询的单个经理时遇到问题。几十个管理器怎么样?选择、更新、插入、删除并连接到其他管理器以及所有这些都具有适当的事务范围和错误处理?

这就是为什么人们尽可能坚持使用 ORM 并且不重新发明轮子的原因。编写一个好的、可重用的数据访问层并不容易,尽管您可能有一个适用于一两个简单案例的有效解决方案,但由于我已经提到的原因,这不会很好地扩展迟早你会得到一大堆纯粹的混乱,在两到三个不成功的方法之后,你最终会重新发明 ORM。

于 2013-11-12T20:08:54.123 回答