FromSqlRawとEF Core 3.1のストアドプロシージャに含める


8

だからここに契約があります-私は現在EF Core 3.1を使用していて、エンティティがあるとしましょう:

public class Entity
{
    public int Id { get; set; }
    public int AnotherEntityId { get; set; }
    public virtual AnotherEntity AnotherEntity { get; set; }
}

DbSet<Entity> Entities通常の方法でアクセスするときは、次のようなAnotherEntityを含めます。

_context.Entities.Include(e => e.AnotherEntity)

そしてこれはうまくいきます。なぜでしょうか?次に私は行きます:

_context.Entities.FromSqlRaw("SELECT * FROM Entities").Include(e => e.AnotherEntity)

これも機能します。どちらも、AnotherEntityで結合された同じオブジェクトのコレクションを返します。次に、SELECT * FROM EntitiesspGetEntitiesという名前の同じクエリで構成されるストアドプロシージャを使用します。

_context.Entities.FromSqlRaw("spGetEntities")

何だと思う?これも機能します。同じ出力が得られますが、明らかにAnotherEntityに参加していません。ただし、次のようにインクルードを追加しようとすると、

_context.Entities.FromSqlRaw("spGetEntities").Include(e => e.AnotherEntity)

私は得ています:

FromSqlRawまたはFromSqlInterpolatedが、構成不可能なSQLとそれを構成するクエリで呼び出されました。AsEnumerable FromSqlRawまたはFromSqlInterpolatedメソッドの後に呼び出して、クライアント側でコンポジションを実行することを検討してください。

_context.Entities.FromSqlRaw("SELECT * FROM Entities")との出力_context.Entities.FromSqlRaw("spGetEntities") は同じですが。

私はEF Core 3.1でこれを行うことができる、またはできないという証明を見つけることができませんでしたが、誰かが私にこのアプローチの可能性のヒントを与えることができれば、それは素晴らしいでしょう。

また、ストアドプロシージャを使用して結合エンティティを取得する別の方法がある場合、問題の解決策としてそれを受け入れるでしょう。


2
これを実行できないのはEFではありません。これはSQL自体(「非構成可能SQL」)なので、EFはもちろん可能です。
Gert Arnold

@GertArnoldを回答として追加してください。他のユーザーにも役立ちます。
Lutti Coelho

_context.Something.FromSqlRaw( "EXECUTE dbo.spCreateSomething @Id、@Year"、sqlParameters).IgnoreQueryFilters()。AsNoTracking()。AsEnumerable()。FirstOrDefault(); これは私にとっては機能します.ToAs()と.AsEnumerable()。FirstOrDefault()を使用して多くを取得できます。
Chris Go、

回答:


6

まもなく、それはできません(少なくともSqlServerの場合)。説明はEFコアのドキュメントに含まれている- 生SQLクエリ - LINQと作曲します

EF Coreは提供されたSQLをサブクエリとして扱うため、LINQで構成するには、生のSQLクエリを構成可能にする必要があります。で構成できるSQLクエリは、SELECTキーワードで始まります。さらに、渡されるSQLには、次のようなサブクエリで無効な文字やオプションを含めないでください。

  • 末尾のセミコロン
  • SQL Serverでは、末尾のクエリレベルのヒント(たとえばOPTION (HASH JOIN)
  • SQL Server上ORDER BYで使用されていない節OFFSET 0 OR TOP 100 PERCENTSELECT

SQL Serverでは、ストアドプロシージャの呼び出しに対する構成は許可されていないため、そのような呼び出しに追加のクエリ演算子を適用しようとすると、SQLが無効になります。使用AsEnumerableまたはAsAsyncEnumerable方法直後FromSqlRawまたはFromSqlInterpolatedメソッドEFコアは、ストアドプロシージャを超える構成しようとしないことを確認してくださいします。

また、Include/ ThenIncluderequire EF CoreなのでIQueryable<>AsEnumerable/ AsAsyncEnumerableなどはオプションではありません。本当に構成可能なSQLが必要なので、ストアドプロシージャはオプションではありません。

ただし、ストアドプロシージャの代わりに、テーブル値関数(TVF)またはデータベースビューを使用できます。これらは構成可能(select * from TVF(params)またはselect * from db_view)だからです。


私は派生型を使用しているため、これは私の場合には機能しません。モデルで使用されている型からの派生型を使用する場合、FromSqlRawの直後にAsEnumerableを呼び出してもクエリは作成されます。他の解決策はありませんが、その型を派生型にせず、すべてのプロパティを基本型から分離するのは不便です。
Hrvoje Batrnek

1
@HrvojeBatrnek私はあなたの心の中に持っていると思いますstackoverflow.com/questions/61070935/...
イワンStoev

2

私の場合FromSql()、ストアドプロシージャ2.1のコードを使用して、動作するEF を3.1 に変換していました。そのようです:

ctx.Ledger_Accounts.FromSql("AccountSums @from, @until, @administrationId",
                                                            new SqlParameter("from", from),
                                                            new SqlParameter("until", until),
                                                            new SqlParameter("administrationId", administrationId));

AccountSumsSPはどこですか。

私がしなければならない唯一のことは、それを再びFromSqlRaw()機能さIgnoreQueryFilters()せるために使用して追加することでした。そのようです:

ctx.Ledger_Accounts.FromSqlRaw("AccountSums @from, @until, @administrationId",
               new SqlParameter("from", from),
               new SqlParameter("until", until),
               new SqlParameter("administrationId", administrationId)).IgnoreQueryFilters();

これはコメントで言及されていますが、私は最初にそれを逃したので、ここにこれを含めます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.