我添加了sql参数,但收到错误“未添加”

问题描述 投票:0回答:1

“过程或函数“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);
}

问题出在哪里?

c# sql entity-framework stored-procedures
1个回答
0
投票

此代码存在几个问题,即使它有效,也会使其非常慢 - 它仅滥用 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 Core 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();

这不是字符串插值操作。格式化字符串用于生成参数并填充它们的值。

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();
© www.soinside.com 2019 - 2024. All rights reserved.