ADO.Net中的SQL函数没有返回/显示值

时间:2013-08-15 07:57:14

标签: sql database ado.net

我对c#很新,我有这个任务。部分原因是让功能发挥作用。我没有收到任何错误,但我在运行时也没有收到任何回复。你能看一下我的代码并告诉我如何在文本框和消息框中显示返回的“钱”吗?

private void button2_Click(object sender, EventArgs e)
    {
       SqlConnection conn = Database.GetConnection();

       SqlDataReader rdr = null;

       using (SqlConnection a = Database.GetConnection())
       using (SqlCommand cmd = new SqlCommand("SELECT CalcRentalCharge", a))
            cmd.CommandType = CommandType.StoredProcedure;
            string CarRentalNo = "1";
       try
       {
            conn.Open();

            SqlCommand cmd = new SqlCommand(
            "CalcRentalCharge", conn);

            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add(
            new SqlParameter("@RentalStartDateTime", RentalStartDateTimeBox.Text));
            cmd.Parameters.Add(
            new SqlParameter("@RentalEndDateTime", RentalEndDateTimeBox.Text));
            cmd.Parameters.Add(
                new SqlParameter("@CarTypeID", CarTypeID.Text));
            rdr = cmd.ExecuteReader();


            while (rdr.Read())
            {
                RentalChargeBox.Text = rdr["@Money"].ToString();                      

                MessageBox.Show("@Money");

            }}

        catch
        {
            if (conn != null)
            {
                conn.Close();
            }
            if (rdr != null)
            {
                rdr.Close();
            }
        }   
    }

存储过程如下所示:

USE [CarRental_P117365]
GO
/****** Object:  UserDefinedFunction [dbo].[CalcRentalCharge]    Script Date:         8/15/2013 09:06:09 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO

/* Create Function CalcFinanceMonthlyPayment to calculate finance monthly repayment */
ALTER FUNCTION [dbo].[CalcRentalCharge] (
@CarTypeID              INT,
@RentalStartDateTime    DATETIME,
@RentalEndDateTime      DATETIME) RETURNS MONEY   

AS
   BEGIN
    DECLARE @NumDays        INT
    DECLARE @DailyRate      MONEY

IF (IsNull(@CarTypeID, 0) <= 0) OR (@RentalStartDateTime IS NULL) OR     (@RentalEndDateTime IS NULL) OR (@RentalEndDateTime <= @RentalStartDateTime)
    RETURN 0

SELECT @DailyRate = DailyRate FROM CarType WHERE CarTypeID = @CarTypeID
IF (IsNull(@DailyRate, 0) <= 0)
    RETURN 0

SELECT @NumDays = CEILING(DATEDIFF(mi, @RentalStartDateTime, @RentalEndDateTime)/ 1440.00)
RETURN CONVERT(MONEY, @NumDays * @DailyRate)
END

2 个答案:

答案 0 :(得分:1)

可能值得在代码中指出一个致命但明显的缺陷。你的存储过程是一个存储过程,你实际上向我们展示了一个用户定义的FUNCTION,这对于它在被调用时失败是完全合理的,就好像它在SP的位置一样。你没有收到错误的原因是你在C#方面有一个catch块,它对错误绝对没有任何意义,只是吞下并隐藏它,而这在C#中是禁止的。我可以想到解决这个问题的各种方法,因为问题似乎更像是设计问题而不是技术问题。

首先,在执行任何其他操作之前,请确保在C#端进行适当的错误处理。您的catch块至少应该为您提供一些线索,告诉您失败的原因,在某处记录错误,显示消息或其他内容,如果您无法做任何更好的事情,即使没有try/catch一切都好,因为你会得到一个错误,而不是一个无声的失败。

现在针对实际问题。在SQL端,您的FUNCTION对输入参数进行一些计算,然后从DB获取数据以执行进一步的计算。一般来说,函数内部的数据访问不是一个好主意,但是因为你将从客户端调用它并没有那么大的伤害。顺便说一句,您是否将此函数作为其他查询/存储过程/视图/其他内容的一部分,在此问题的范围之外?如果没有,也许它值得成为一个真正的SP。

由于FUNCTION只能作为查询的一部分调用,要直接从客户端调用它,您应该提交一个查询,可能只是在虚拟SELECT语句中调用它。可能这是现在使用此FUNCTION的最简单方法。 这可以通过改变C#端的一部分来完成:

private void button2_Click(object sender, EventArgs e)
{
   try
   {
       using (SqlConnection connection = Database.GetConnection())
       {
           using (SqlCommand cmd = new SqlCommand("SELECT dbo.CalcRentalCharge(@RentalStartDateTime,@RentalEndDateTime,@CarTypeID)", connection))
           {
               cmd.CommandType = CommandType.Text;
               cmd.Parameters.Add("@RentalStartDateTime", SqlDbType.DateTime).Value = RentalStartDateTimeBox.Text;
               cmd.Parameters.Add("@RentalEndDateTime", SqlDbType.DateTime).Value =  RentalEndDateTimeBox.Text;
               cmd.Parameters.Add("@CarTypeID", SqlDbType.Int).Value = CarTypeID.Text;

               connection.Open();
               decimal rentalChange = (decimal)cmd.ExecuteScalar();
               connection.Close();

               MessageBox.Show("The rental change is: " + rentalChange.ToString());
           }
       }
   }
   catch(Exception ex)
   {
       MessageBox.Show(ex.ToString());
   }
}

答案 1 :(得分:0)

有几点:

您的潜在参数类型不匹配。您存储的proc获取2个DATETIME参数,而您实际传递字符串。因此,您需要将两个DATETIME参数修复为:

cmd.Parameters.Add(new SqlParameter("@RentalStartDateTime", SqlDbType.DateTime)
{
   Value = DateTime.Parse(RentalStartDateTimeBox.Text)
});

您必须指明您的存储过程有一个输出参数(添加到参数列表):

@retVal MONEY output

您必须实际返回正确的值,因此您的proc(它的最后部分)应更改为:

SET @retVal = CONVERT(MONEY, @NumDays * @DailyRate)
RETURN @retVal

您需要指明您想要接收的返回值,因此代码从行开始&#34; rdr = cmd.ExecuteReader();&#34;应改为:

SqlParameter retval = cmd.Parameters.Add("@retVal", SqlDbType.Money);
retval.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
double retunvalue = (double) cmd.Parameters["@retval"].Value;

另外,请注意(a)您不必使用阅读器,(b)调用存储过程是非查询操作(而不是阅读器操作)。