提问人:Musa AKYUZ 提问时间:10/27/2023 最后编辑:CharliefaceMusa AKYUZ 更新时间:10/27/2023 访问量:59
我添加了 sql 参数,但出现错误“未添加”
I add sql parameters but I get the error "not added"
问:
我收到此错误:
过程或函数“GetCurrencyAtDate”需要参数“@soruceCurrencyId”,但未提供该参数。
这是我的存储过程:
ALTER PROCEDURE [dbo].[GetCurrencyAtDate]
@soruceCurrencyId int,
@targetCurrencyId int,
@year int,
@month int,
@day int,
@result decimal OUTPUT
AS
BEGIN
DECLARE @targetDate DATETIME
SET @targetDate = DATEADD(DAY, @day - 1, DATEADD(MONTH, @month - 1, DATEADD(YEAR, @year - 1900, 0)))
SELECT TOP 1 @result = Currency
FROM KurTable
WHERE SourceKur = @soruceCurrencyId
AND TargetKur = @targetCurrencyId
AND Date <= @targetDate
ORDER BY ABS(DATEDIFF(DAY, Date, @targetDate));
END
我正在使用 Entity Framework Core 并通过函数编写命令:DbContext
using (var context = new EfDataContext())
{
var date = DateTime.Now;
var year = date.Year;
var month = date.Month;
var day = date.Day;
var resultParameter = new SqlParameter
{
ParameterName = "@result",
Direction = ParameterDirection.Output,
SqlDbType = SqlDbType.Decimal,
};
var command = context.Database.GetDbConnection().CreateCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "GetCurrencyAtDate";
command.Parameters.Add(new SqlParameter("@sourceCurrencyId", SqlDbType.Int) { Value = sourceCurrency });
command.Parameters.Add(new SqlParameter("@targetCurrencyId", SqlDbType.Int) { Value = targetCurrency });
command.Parameters.Add(new SqlParameter("@year", SqlDbType.Int) { Value = year });
command.Parameters.Add(new SqlParameter("@month", SqlDbType.Int) { Value = month });
command.Parameters.Add(new SqlParameter("@day", SqlDbType.Int) { Value = day });
command.Parameters.Add(resultParameter);
context.Database.OpenConnection();
var result = await command.ExecuteScalarAsync();
currencyValue = Convert.ToDecimal(result);
}
问题出在哪里?
答:
此代码存在几个问题,即使它有效,也会使其非常慢 - 它滥用 EF Core 仅执行 ADO.NET 代码,忘记关闭连接,存储过程本身过于复杂,例如用于执行也会执行的操作。日期作为部分传递,然后以复杂的方式重建,而不是使用ABS(DATEDIFF(DAY, Date, @targetDate))
ORDER BY Date
DATEFROMPARTS
以下所有选项都可以与存储过程一起使用,但在这种情况下,它只是不需要。
要从表格中实际获取最新汇率,您只需要使用 Dapper 来减少样板:
var sql=@" SELECT TOP 1 Currency
FROM KurTable
WHERE SourceKur = @fromCur
AND TargetKur = @toCur
AND Date <= @date
ORDER BY Date DESC";
using (var con=new SqlConnection(connectionString))
{
var rate=con.ExecuteScalar<decimal>(sql,new {
fromCur=sourceCurrency,
toCur=targetCurrency,
date=DateTime.Today
});
}
就这样。Dapper 将创建一个 SqlCommand,其参数基于匿名类型属性,使用相同的名称和类型,打开连接,执行查询,返回结果并关闭连接。它还将对命令和映射进行处理,以便下次不必重新生成它。
在此示例中,连接是在块中创建的,因此一旦块退出,它就会被释放。using
如果需要,也可以直接使用 DbContext 的连接。
var con=context.Database.GetDbConnection();
var rate=con.ExecuteScalar<decimal>(sql,new {
fromCur=sourceCurrency,
toCur=targetCurrency,
date=DateTime.Today
});
EF 核心 7
EF Core 7 也使用 SqlQuery 提供相同的功能:
var rate=context.Database
.SqlQuery<decimal>($@"SELECT Currency
FROM KurTable
WHERE SourceKur = {sourceCurrency}
AND TargetKur = {targetCurrency}
AND Date <= {targetDate}
ORDER BY Date DESC")
.FirstOrDefault();
这不是字符串插值操作。formattable 字符串用于生成参数并填充其值。
SqlQuery 返回一个 IQueryable<>这意味着我们也可以使用它来指定排序顺序:OrderByDescending
var rate=context.Database
.SqlQuery<decimal>($@"SELECT Currency,Date
FROM KurTable
WHERE SourceKur = {sourceCurrency}
AND TargetKur = {targetCurrency}
AND Date <= {targetDate}")
.OrderByDescending(c=>c.Date)
.Select(c=>c.Currency)
.FirstOrDefault();
当然,如果表是一个实体,我们可以只编写一个 LINQ 查询。
var rate=context.ExchangeRates
.Where(xr=>xr.SourceCurrency==sourceCurrency &&
xr.TargetCurrency==targetCurrency &&
xr.Date <= targetDate)
.OrderByDescending(xr=>xr.Date)
.Select(xr=>xr.Currency)
.FirstOrDefault();
使用存储过程
返回特定日期的最新汇率的存储过程如下所示:
ALTER PROCEDURE [dbo].[GetCurrencyAtDate]
@sourceCurrencyId INT,
@targetCurrencyId int,
@targetDate DATE
AS
BEGIN
SELECT TOP 1 Currency
FROM KurTable
WHERE SourceKur = @soruceCurrencyId
AND TargetKur = @targetCurrencyId
AND Date <= @targetDate
ORDER BY Date DESC
END
这可以使用 Dapper 或 EF Core 7 调用:
var rate= con.ExecuteScalar<decimal>("GetCurrencyAtDate",
new {
sourceCurrencyId =sourceCurrency,
targetCurrencyId =targetCurrency,
targetDate =DateTime.Today
},
commandType: CommandType.StoredProcedure);
在 EF Core 7 中:
var rate=context.Database
.SqlQuery<decimal>($"exec GetCurrencyAtDate
@sourceCurrencyID={sourceCurrency},
@targetCurrencyId= {targetCurrency},
@targetDate = {targetDate}")
.FirstOrDefault();
评论
只需使用 NULL 默认值声明存储过程参数即可。
ALTER PROCEDURE [dbo].[GetCurrencyAtDate]
@soruceCurrencyId int = NULL,
@targetCurrencyId int = NULL,
@year int = NULL ,
@month int = NULL,
@day int = NULL,
@result decimal OUTPUT
评论
@soruceCurrencyId
@sourceCurrencyId
sourceCurrencyId
soruceCurrencyId
resultParameter
currencyValue = resultParameter.Value;