0

我是 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
4

2 回答 2

1

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

首先,在做任何其他事情之前,请确保在 C# 端进行正确的错误处理。你的catch块至少应该给你一些关于它为什么失败的线索,在某处记录错误,显示一条消息或其他什么,如果你不能做任何更好的事情,即使没有try/catch更好,因为你会得到一个错误而不是无声的失败。

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

由于FUNCTIONs 只能作为查询的一部分调用,因此要直接从客户端调用它,您应该提交一个查询,它可能只是在一个虚拟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());
   }
}
于 2013-08-16T00:42:23.763 回答
0

几点:

您有潜在的参数类型不匹配。您的存储过程获得 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

你需要指出有一个你想要接收的返回值,所以代码从“rdr = cmd.ExecuteReader();”这一行开始 应改为:

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

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

于 2013-08-15T08:57:29.430 回答