C# 以Datatable的形式从存储过程获取数据

C# 以Datatable的形式从存储过程获取数据,c#,sql-server,winforms,C#,Sql Server,Winforms,我有一种方法可以使用存储过程作为DataTable从数据库检索数据,如: public DataTable GetTableBySQL(string sql) { SqlCommand cmd = new SqlCommand(sql.ToString(), this.dbconn) { CommandTimeout = 0, CommandType = CommandType.Text }; DataTable tbl =

我有一种方法可以使用存储过程作为DataTable从数据库检索数据,如:

public DataTable GetTableBySQL(string sql) 
{
    SqlCommand cmd = new SqlCommand(sql.ToString(), this.dbconn) 
    {
        CommandTimeout = 0,
        CommandType = CommandType.Text
    };

    DataTable tbl = new DataTable("Table1") 
    {
        Locale = System.Globalization.CultureInfo.InvariantCulture
    };

    SqlDataAdapter da = new SqlDataAdapter(cmd);

    try 
    {
        da.SelectCommand.CommandTimeout = 0;
        da.Fill(tbl);
    } 
    catch (SqlException e) 
    {
        this.HandleSQLError(e, "GetTableBySQL", sql.ToString());
    }
    finally
    {
        cmd.Dispose();
        da.Dispose();
    }

    return tbl;
}
现在我这样调用存储过程:

var empList = db.GetTableBySQL("$exec getMySP");
public DataTable GetTableBySQL(string sql, params SqlParameter[] parameters) 
{
    var result = new DataTable();

    //ADO.Net really does work better when you create a **NEW** connection
    //  object for most queries. Just share the connection string.
    //Also: "using" blocks are a better way to make sure the connection is closed.
    using (var dbconn = new SqlConnection(this.dbConnectionString))
    using (var cmd = new SqlCommand(sql, dbconn))
    using (var da = new SqlDataAdapter(cmd))
    {
        cmd.CommandTimeout = 0;
        // A number of the properties set on the cmd and tbl variables just set the same value that was already there, didn't accomplish anything

        //It's hard to understate how important it is to use parameterized queries.
        if (parameters != null && parameters.Length > 0)
        {
            cmd.Parameters.AddRange(parameters);
        }

        try
        {
            da.Fill(result);
        } 
        catch (SqlException e) 
        {
            this.HandleSQLError(e, "GetTableBySQL", sql.ToString());
            //you may want to re-throw here, 
            // or even just remove the try/catch and let the error bubble up to calling code
        }
    }  
    return result;
}
var empList = db.GetTableBySQL("exec getMySP");
但当我执行时,它不会返回任何列


我做错了什么?关于

这里有三个主要问题,其他较小的问题,但有三个是重要的:

SQL的$exec部分没有任何意义。也许你只是想要执行官。 当坏SQL失败时,程序会隐藏错误,因此您不知道发生了什么。 方法签名不支持查询参数,因此将迫使您编写极不安全的代码,这将导致有人入侵您的应用程序。可能早一点,而不是晚一点。这真的很糟糕,你不应该忽视它。 尝试类似以下内容:

var empList = db.GetTableBySQL("$exec getMySP");
public DataTable GetTableBySQL(string sql, params SqlParameter[] parameters) 
{
    var result = new DataTable();

    //ADO.Net really does work better when you create a **NEW** connection
    //  object for most queries. Just share the connection string.
    //Also: "using" blocks are a better way to make sure the connection is closed.
    using (var dbconn = new SqlConnection(this.dbConnectionString))
    using (var cmd = new SqlCommand(sql, dbconn))
    using (var da = new SqlDataAdapter(cmd))
    {
        cmd.CommandTimeout = 0;
        // A number of the properties set on the cmd and tbl variables just set the same value that was already there, didn't accomplish anything

        //It's hard to understate how important it is to use parameterized queries.
        if (parameters != null && parameters.Length > 0)
        {
            cmd.Parameters.AddRange(parameters);
        }

        try
        {
            da.Fill(result);
        } 
        catch (SqlException e) 
        {
            this.HandleSQLError(e, "GetTableBySQL", sql.ToString());
            //you may want to re-throw here, 
            // or even just remove the try/catch and let the error bubble up to calling code
        }
    }  
    return result;
}
var empList = db.GetTableBySQL("exec getMySP");
这里同样没有所有额外的解释性注释,因此您可以看到正确操作代码更少,而不是更多:

public DataTable GetTableBySQL(string sql, params SqlParameter[] parameters) 
{
    var result = new DataTable();

    using (var dbconn = new SqlConnection(this.dbConnectionString))
    using (var cmd = new SqlCommand(sql, dbconn))
    using (var da = new SqlDataAdapter(cmd))
    {
        cmd.CommandTimeout = 0;
        if (parameters != null && parameters.Length > 0)
        {
            cmd.Parameters.AddRange(parameters);
        }

        da.Fill(result);
    }  
    return result;
}
那么就这样称呼它:

var empList = db.GetTableBySQL("$exec getMySP");
public DataTable GetTableBySQL(string sql, params SqlParameter[] parameters) 
{
    var result = new DataTable();

    //ADO.Net really does work better when you create a **NEW** connection
    //  object for most queries. Just share the connection string.
    //Also: "using" blocks are a better way to make sure the connection is closed.
    using (var dbconn = new SqlConnection(this.dbConnectionString))
    using (var cmd = new SqlCommand(sql, dbconn))
    using (var da = new SqlDataAdapter(cmd))
    {
        cmd.CommandTimeout = 0;
        // A number of the properties set on the cmd and tbl variables just set the same value that was already there, didn't accomplish anything

        //It's hard to understate how important it is to use parameterized queries.
        if (parameters != null && parameters.Length > 0)
        {
            cmd.Parameters.AddRange(parameters);
        }

        try
        {
            da.Fill(result);
        } 
        catch (SqlException e) 
        {
            this.HandleSQLError(e, "GetTableBySQL", sql.ToString());
            //you may want to re-throw here, 
            // or even just remove the try/catch and let the error bubble up to calling code
        }
    }  
    return result;
}
var empList = db.GetTableBySQL("exec getMySP");

在c语言中,我们使用$进行插值,所以你们可以使用string.Format,我发现了这个问题。调用SP的正确方法是db.GetTableBySQL$exec getMySP;,你的答案也是正确的。谢谢,但是这个字符串中没有插值大括号,所以你要求语言做额外的工作,寻找不会改变任何东西的大括号。只需从这个字符串中删除$,并且只在需要时使用它。对。非常感谢。