在c#中从db层调用sprocs

时间:2009-06-15 15:57:06

标签: c# database stored-procedures

假设您有一些简单的sprocs,例如

AddXYZ(param1,param 2 ... etc)

getAllXYZ()

getXYZ(ID)

从“db layer”

调用这些sprocs的“最佳实践”方法是什么?

我不想使用linq。关于如何做到这一点的简单c#静态方法。

即时使用sqlserver。

5 个答案:

答案 0 :(得分:8)

我认为你并不真正意味着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
            }
        }
    }
}

您没有指定要连接的数据库引擎,因此我使用了通用接口来抽象您。如果你愿意(虽然我通常不会对执行此操作的代码感到不满),你可以使用特定于平台的类,使事情变得更加容易,至少在添加参数方面(代码不像基于接口的方法那样冗长)< / p>

答案 1 :(得分:5)

这是你在找什么?

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

答案 2 :(得分:1)

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

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
}

然后,您在数据层中提供与要提供给业务层的接口匹配的公共方法。在一个设计良好的应用程序中,这通常会与存储过程相匹配,这听起来就像你想要的那样,但有时它并不能很好地工作。例如,您可能需要从一个方法调用多个过程。

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

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;
    }
}

答案 3 :(得分:0)

通常,您需要查看SQLConnection和SQLCommand类(假设您正在连接到SQL db,当然)。您将SQLCommand.CommandText属性设置为“EXEC AddXYZ @X,@ Y,@ Z”,然后对@X,@ Y和@Z使用SQLCommand.Parameters.AddWithValue()。

然后,您将调用SQLCommand的相应执行方法(NonQuery,Scalar或Reader)。

答案 4 :(得分:0)

托马斯的榜样是标准方式。我建议您查看以下内容以获得进一步的帮助:

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