我对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
答案 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)调用存储过程是非查询操作(而不是阅读器操作)。