web-dev-qa-db-ja.com

EF Core 3.0でFromSqlInterpolatedを使用して複数のパラメーターのストアドプロシージャを実行する方法

SQL Server 2017にストアドプロシージャがあり、3つのパラメーターを取ります。

CREATE PROCEDURE UpdateRestaurantInformation
@restaurantId nvarchar(max),
@restaurantName nvarchar(max),
@locationId int
AS
BEGIN
    UPDATE Restaurants
    SET RestaurantName = @restaurantName, LocationId = @locationId
    WHERE RestaurantId = @restaurantId;

    SELECT * FROM Restaurants WHERE RestaurantId = @restaurantId;
END

以下のコードスニペットを使用してこのストアドプロシージャを実行しようとすると、予想どおりIt worksになりました。

   SqlParameter param1 = new SqlParameter("@p0",restaurant.RestaurantId);
   SqlParameter param2 = new SqlParameter("@p1", restaurant.RestaurantName);
   SqlParameter param3 = new SqlParameter("@p2", restaurant.Location.LocationId);

     var res = _context.Restaurants
    .FromSqlRaw("UpdateRestaurantInformation @p0,@p1,@p2", param1, param2, param3)
    .ToList();

しかし、以下のようにFromSqlInterpolatedを使用しようとしたとき:

var res = await _context.Restaurants
   .FromSqlInterpolated(
   $"UpdateRestaurantInformation {restaurant.RestaurantId}, {restaurant.RestaurantName}, {restaurant.Location.LocationId}")
   .SingleAsync();

この例外をスローしています:

SqlException: '@ p0'付近の構文が正しくありません。 Microsoft.Data.SqlClient.SqlCommand + <> c.b__164_0(タスク結果)

ここで何を間違えていますか?誰か助けてください。

次の記事では、efコアでsqlコマンドを使用する方法を学ぶことができます。

https://www.learnentityframeworkcore.com/raw-sql#stored-procedureshttps://www.learnentityframeworkcore.com/raw-sql#database.executesqlcommand

efcoreが更新されました。新しいefcore apiでSqlParameterをビルドする必要はありません。

ExecuteSqlCommandAsyncとFromSqlは廃止されました。これはコードコメントで確認できます。

[Obsolete("For the async execution of SQL queries using plain strings, use ExecuteSqlRawAsync instead. For the async execution of SQL queries using interpolated string syntax to create parameters, use ExecuteSqlInterpolatedAsync instead.")]
public static Task<int> ExecuteSqlCommandAsync([NotNull] this DatabaseFacade databaseFacade, RawSqlString sql, [NotNull] IEnumerable<object> parameters, CancellationToken cancellationToken = default);

[Obsolete("For returning objects from SQL queries using plain strings, use FromSqlRaw instead. For returning objects from SQL queries using interpolated string syntax to create parameters, use FromSqlInterpolated instead. Call either new method directly on the DbSet at the root of the query.", true)]
public static IQueryable<TEntity> FromSql<TEntity>([JetBrains.Annotations.NotNull] this IQueryable<TEntity> source, [JetBrains.Annotations.NotNull] [NotParameterized] FormattableString sql) where TEntity : class

パラメータ付きの新しいAPIは次のとおりです。

public static Task<int> ExecuteSqlInterpolatedAsync([JetBrains.Annotations.NotNull] this DatabaseFacade databaseFacade, [JetBrains.Annotations.NotNull] FormattableString sql, CancellationToken cancellationToken = default(CancellationToken))
public static IQueryable<TEntity> FromSqlInterpolated<TEntity>([JetBrains.Annotations.NotNull] this DbSet<TEntity> source, [JetBrains.Annotations.NotNull] [NotParameterized] FormattableString sql) where TEntity : class

これらの新しいAPIは、たとえば、パラメータとしてFormattableStringを使用します。

string parm1="A";
string parm2="B";
_dbContext.Database.ExecuteSqlInterpolatedAsync($"EXEC proc @parm1={parm1},@parm2={parm2}");

@ parm1はデータベースプロシージャで定義され、{parm1}はcsharp文字列parm1値からのものです

FromSql詳細: https://docs.Microsoft.com/en-us/ef/core/querying/raw-sql

1
ws_

だから、これは私が GitHub から得たソリューションです。 @IvanStoevがコメントで述べたように、私がしなければならなかったのは、SingleOrDefault()をToList()に置き換えることだけでした。

将来誰かがこれを必要とする場合は、ここに追加します。

var res = await _context
           .Restaurants
           .FromSqlInterpolated($"UpdateRestaurantInformation {restaurant.RestaurantId}, {restaurant.RestaurantName}, {restaurant.Location.LocationId}").ToListAsync();

return res.SingleOrDefault();