【问题标题】:Calling SQL Functions directly from C#直接从 C# 调用 SQL 函数
【发布时间】:2011-03-02 02:08:07
【问题描述】:

我需要对将返回零或一的数据库运行查询 (检查是否存在特定标准)。 我获得的技术规范表明我应该创建一个存储过程,它将返回一行,一个名为“result”的列将包含一个位值 0 或 1。 但是,我不确定存储过程是否是最好的方法,但我有点不确定,所以我想问问你的意见。 我能想到的两个选项是:

1:创建一个执行查询并返回位的 SQL 标量值函数。 然后可以使用“TEXT”SqlCommand 对象从 .Net 客户端应用程序中直接调用它,它会从“ExecuteScalar()”方法返回一个布尔值。

2:按照技术规范中的说明创建存储过程。 然后,它会以正常方式从 .Net 客户端应用程序中调用,并返回一个包含位值的单行单列 DataTable。

对我来说,选项一似乎是最好的。然而,我的脑海里有一些东西在说这不是一个好主意。

请您发表您的意见并帮助减轻我的担忧吗? :)

干杯, 伊恩

【问题讨论】:

  • 对于这样的单个结果,使用 DataReader 或 DataAdapter 是多余的。使用 ExecuteScalar() 方法。
  • 谢谢 Jeff - 在以下答案之一出现之前,我实际上并不知道您可以针对存储过程执行此操作:)

标签: sql sql-server stored-procedures user-defined-functions


【解决方案1】:

使用 ExecuteScalar() 方法执行存储过程。然后,您可以将其结果转换为布尔值。

例如

   SqlConnection con = new SqlConnection(connectionString);
    SqlCommand com = new SqlCommand("Execute dbo.usp_MyStoredProc", con);
    return (Boolean)com.ExecuteScalar();

【讨论】:

  • 虽然我喜欢这种方法,但 TcKs 的 cmets 在他的回答中让我相信,在这种情况下,我不应该将存储过程用作函数,而应该将函数用作函数。但是无论如何,谢谢-无论如何,我从您的回答中学到了一些新东西:)
【解决方案2】:

这对我有用,并且基于此答案 https://stackoverflow.com/a/3232556/1591831 使用 SqlDataAdapter(请注意,您不需要使用)和 ExecuteScalar(可以使用 ExecuteNonQuery,如此处所示):

bool res = false;
using (SqlConnection conn = new SqlConnection(GetConnectionString()))
{
    using (SqlCommand comm = new SqlCommand("dbo.MyFunction", conn))
    {
        comm.CommandType = CommandType.StoredProcedure;

        SqlParameter p1 = new SqlParameter("@MyParam", SqlDbType.Int);
        // You can call the return value parameter anything, .e.g. "@Result".
        SqlParameter p2 = new SqlParameter("@Result", SqlDbType.Bit);

        p1.Direction = ParameterDirection.Input;
        p2.Direction = ParameterDirection.ReturnValue;

        p1.Value = myParamVal;

        comm.Parameters.Add(p1);
        comm.Parameters.Add(p2);

        conn.Open();
        comm.ExecuteNonQuery();

        if (p2.Value != DBNull.Value)
            res = (bool)p2.Value;
    }
}
return res;

【讨论】:

    【解决方案3】:

    调用标量值函数是绝对正确的解决方案。

    【讨论】:

    • 因为,如何从数据库引擎获取任何结果的选择有限。基本上你只有“SELECT”命令。 “ExecuteScalar”方法很智能,可以从标量值函数或常量(“SELECT @@SERVERNAME”)或第一行第一列的值(“SELECT A, B, C FROM MyTable”)中检索值。
    • 所以,要仔细检查您的意思,使用“sqlCommand.ExecuteScalar()”方法(如 Barry 所示)执行存储过程是正确的解决方案吗?抱歉 - 只是想确保我理解准确:)
    • 通常使用标量值函数比使用存储过程更好。这是因为标量值函数具有强类型结果。一个过程可以有多个结果(多个表结果和一个标量结果和多个输出参数)。例如,存储过程不能在“WHERE”子句中使用。等等。然而,该过程有更多的选择可以做什么。功能/程序的决定取决于场景,你想解决。
    • 那么我相信标量值函数是正确的答案,因为这个任务实际上是一个“FileExists”函数。谢谢。
    【解决方案4】:

    我想这取决于相应的 db 函数 (sp/udf) 必须执行的逻辑。

    如果例如我们对特定 db 函数执行的次数感兴趣,我们肯定需要对各种表进行一些数据操作和更新。因此,我们必须在这里存储过程。如果它是一个简单的检索,一个 udf 就可以了。

    【讨论】:

      【解决方案5】:

      从长远来看,使用存储过程解决它会更好,因为它更灵活且适应性强

      【讨论】:

      • 更好和更灵活纯粹是主观的,基于逻辑来确定结果。如果不了解逻辑,就无法准确地做出该断言。
      • 确实如此。我只是想如果你把它实现为一个存储过程,你可以通过多种方式更新逻辑,例如你可以在其中使用一个标量值函数我认为在这种情况下存储过程更像是一种包装器
      【解决方案6】:

      我使用这个 sql 标量函数

      CREATE FUNCTION DAYSADDNOWK(@addDate AS DATE, @numDays AS INT)
      RETURNS DATETIME
      AS
      BEGIN
          SET @addDate = DATEADD(d, @numDays, @addDate)
          IF DATENAME(DW, @addDate) = 'sunday'   SET @addDate = DATEADD(d, 1, @addDate)
          IF DATENAME(DW, @addDate) = 'saturday' SET @addDate = DATEADD(d, 2, @addDate)
      
          RETURN CAST(@addDate AS DATETIME)
      END
      GO
      

      那么这是我的 c# 代码

      using (SqlCommand cmd3 = new SqlCommand("SELECT dbo.DAYSADDNOWK", ClassV.con))
                          ClassV.con.Open();
                          SqlCommand brecord = ClassV.con.CreateCommand();
                          brecord.CommandText = "INSERT INTO TblBorrowRecords VALUES ('" + DGStudents.CurrentRow.Cells[1].Value.ToString() + "','" + DGStudents.CurrentRow.Cells[2].Value.ToString() + "','" + DGStudents.CurrentRow.Cells[4].Value.ToString() + "','" + DGStudents.CurrentRow.Cells[3].Value.ToString() + "','" + DG.CurrentRow.Cells[4].Value.ToString() + "','" + DG.CurrentRow.Cells[5].Value.ToString() + "','" + DG.CurrentRow.Cells[6].Value.ToString() + "','" +System.DateTime.Now.Date.ToShortDateString() + "' , dbo.DAYSADDNOWK(GETDATE(),5) ,null , '" + ClassV.lname.ToString() + ", " + ClassV.fname.ToString() + " " + ClassV.mname.ToString() + "', null, 'Good',null)";
                          var DAYSADDNOWK = brecord.ExecuteScalar();
      

      我的 C# 代码跳过了这个函数

      【讨论】:

      • 我不会使用该代码,尤其是在生产环境中,由于 SQL 注入,它不安全
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 2015-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多