【问题标题】:calling sprocs from a db layer in c#从 C# 中的 db 层调用 sprocs
【发布时间】:2009-06-15 15:57:05
【问题描述】:

假设你有一些简单的存储过程,例如

AddXYZ(param1, param 2...等)

getAllXYZ()

getXYZ(id)

从“数据库层”调用这些存储过程的“最佳实践”方式是什么

我不想使用 linq。只是简单的 c# 静态方法来说明如何做到这一点。

我正在使用 sqlserver。

【问题讨论】:

    标签: c# database stored-procedures


    【解决方案1】:

    我不认为您真的是指 static 方法,因为这将是一种非常非 OO 的方式来处理这样的事情,并且 C# 中没有内置这样的工具。但是,有标准的 ADO.NET 类可以让您在没有任何 ORM 包装或使用 DataSet 等的情况下执行此操作。-

    如果您真的想手动调用存储过程并在没有任何 ORM 或标准化存储机制的情况下返回一组结果,这将是您最好的选择:

    using(System.Data.IDbConnection conn = /*create your connection here*/)
    {
        using(System.Data.IDbCommand cmd = conn.CreateCommand())
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "AddXYZ";
    
            // add your parameters here using cmd.CreateParameter() and cmd.Parameters.Add()
    
            using(System.Data.IDbDataReader reader = cmd.ExecuteReader())
            {
                while(reader.Read())
                {
                    // read your results row-by-row
                }
            }
        }
    }
    

    您没有指定要通过哪个数据库引擎进行连接,因此我使用了通用接口,可以将您从中抽象出来。如果您愿意(尽管我通常不赞成这样做的代码),您可以使用特定于平台的类,这会使事情变得更容易,至少在添加参数方面(代码不像基于接口的方法那样冗长)

    【讨论】:

    • 您需要担心的不是内存,而是数据库连接。
    【解决方案2】:

    这是你要找的吗?

    SqlCommand cmd  = new SqlCommand("AddXYZ", conn);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add(new SqlParameter("@param1", someValue));
    

    【讨论】:

      【解决方案3】:

      首先,您在数据层中创建一个用于获取连接信息的地方。如果您的数据层仅限于单个类,则这可能是私有成员;如果该层包含整个程序集,则可能是内部项。它可以返回一个连接字符串或一个实际的连接对象本身,但主要的是它根本没有暴露在数据层之外:

      private static ConnectionString { get { // read from config file once.... return ""; } }
      
      private SqlConnection getConnection()
      {
          SqlConnection result = new SqlConnection(ConnectionString);
          result.Open();  // I like to open it in advance, but that's less common
          return result;  // you'll want some error handling code in here as well
      }
      

      然后,您在数据层中提供与您要提供给业务层的接口相匹配的公共方法。在精心设计的应用程序中,这通常会与存储过程相匹配,这听起来像是您想要的,但有时效果并不好。例如,您可能需要从一种方法调用多个过程。

      无论您做什么,该方法都应该接受强类型参数值,以便在调用过程时使用。关于该方法是否应该返回业务对象或数据记录存在一些争论。就个人而言,我倾向于返回数据记录,但提供一个额外的“层”,将数据记录转换为强类型业务对象:

      public IDataRecord GetXYZ(int id)
      {
          DataTable dt = new DataTable();
          using (var cn = getConnection())
          using (var cmd = new SqlCommand("getXYZ"))
          {
              cmd.CommandType = CommandTypes.StoredProcedure;
              cmd.Parameters.Add("@ID", SqlDbType.Int).Value = id;
      
              using (var rdr = cmd.ExecuteReader())
              {
                 dt.Load(rdr);
              }
          }
      
          //obviously put a little more work into your error handling
          if (dt.Rows.Count <= 0)
             throw new Exception("oops");  
      
          return dt.Rows[0];
      }
      
      public class XYZFactory
      {
          public static XZY Create(IDataRecord row)
          {
              XYZ result = new XYZ();
              result.id = row["ID"];
              result.otherfield = row["otherfield"];
              return result;
          }
      }
      

      【讨论】:

        【解决方案4】:

        一般来说,您需要查看 SQLConnection 和 SQLCommand 类(当然,假设您正在连接到 SQL 数据库)。您将 SQLCommand.CommandText 属性设置为类似“EXEC AddXYZ @X, @Y, @Z”,然后对 @X、@Y 和 @Z 中的每一个使用 SQLCommand.Parameters.AddWithValue()。

        然后您将调用 SQLCommand 的适当执行方法(NonQuery、Scalar 或 Reader)。

        【讨论】:

          【解决方案5】:

          Thomas 的示例是标准方法。我建议您查看以下内容以获得更多帮助:

          http://msdn.microsoft.com/en-us/library/aa902662.aspx

          就我个人而言,我编写了一个静态类 (DataHelper),它公开了一堆您可能会使用的方法,例如当您的存储过程返回内容时返回 IDataReader 对象的方法,以及当它们返回时的 void 方法不是,还有一些在 out 参数中返回 Connection 对象,以便您可以保持打开状态。

          该类只是将 ADO.NET 代码包装在 try catch 块中,用于常见问题检查和日志记录/跟踪(DNS 关闭、服务器关闭、svc 关闭),并使用 using 语句确保不浪费资源。我还包装了一个使用 ConnectionStringBuilder 的方法来返回连接字符串,这样我就不必继续编写该代码了。

          我确实发现,对于一个大型项目,对我所有的实体“提供者”进行编码是重复的,我应该设计一个更可重用的配置驱动模型。

          这些天,如果我有新的领域,我会考虑使用 EDM。

          http://msdn.microsoft.com/en-us/library/aa697428(VS.80).aspx

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多