9

Entity Framework(NuGetの最新バージョン)は、最初に定義されたもの以外のナビゲーションプロパティの結合を構築するときに、HasRequired構成を無視している可能性があります。

たとえば、次の構成のPOCOオブジェクト(Person)があるとします。

var person = modelBuilder.Entity<Person>();
person.ToTable("The_Peoples");
person.HasKey(i => i.Id);
person.Property(i => i.Id).HasColumnName("the_people_id");
person.HasRequired(i => i.Address)
    .WithMany()
    .Map(map => map.MapKey("address_id"));
person.HasRequired(i => i.WorkPlace)
    .WithMany()
    .Map(map => map.MapKey("work_place_id"));

次のクエリで人のリストを読み込もうとしています。

myContext.Set<People>()
    .Include(o => o.Address)
    .Include(o => o.WorkPlace);

Entity Frameworkは、次のクエリを生成します。

FROM  [dbo].[The_Peoples] AS [Extent1]
INNER JOIN [dbo].[The_Addresses] AS [Extent2] ON [Extent1].[address_id] = [Extent2].[address_id]
LEFT OUTER JOIN [dbo].[The_Work_Places] AS [Extent3] ON [Extent1].[work_place_id] = [Extent3].[work_place_id]

* The_Addresses *テーブルへの結合は(予想どおり)内部結合ですが、*The_Work_Places*への後続の結合は外部結合であることに注意してください。AddressプロパティとWorkPlaceプロパティの両方が必須としてマークされていることを考えると、両方の結合が内部結合であると予想されます。また、AddressプロパティとWorkPlaceプロパティをRequired属性でマークしようとしましたが、効果がありませんでした。

これはバグですか、それとも私は何かを誤って構成していますか?提案?

4

3 に答える 3

7

モデルの構成は正しく、バグではないと思いますが、仕様による動作ですが、正確にどのような設計かはわかりません。私はまた、そのようなクエリでその SQL を見てきました。いくつかの注意事項:

  • 表示されているクエリは、EF 4.2 に固有のものではありません。また、EF 4.1 および EF 4.0 でも発生します。ただし、EF 1 (.NET 3.5) には対応していません。EF 1 では、これも最初の everyが、必要な関係のために にIncludeマップされています。LEFT OUTER JOIN

  • INNER JOINを使用することは、必要なナビゲーション プロパティに対して「正しい」とは言えず、間違っているとは言えませんLEFT OUTER JOIN。マッピングの観点からは、データベース内の制約がモデル内の関係を正しく表しているのであれば、何を使用しても問題ありません。必要なナビゲーション プロパティの場合、データベースの FK 列は NULL 可能であってはならず、FK がターゲット テーブルの既存の行を参照することを強制する制約がデータベースに存在する必要があります。その場合、またはJOINを使用するかどうかに関係なく、 every は行を返す必要があります。INNER JOINLEFT OUTER JOIN

  • モデルとデータベースが関係に関して「同期していない」場合はどうなりますか? どちらの場合も基本的にナンセンスです。 a を使用しLEFT OUTER JOIN、FK がNULLDB にあるか、存在しない行を参照している場合、ナビゲーション プロパティが であるエンティティが取得nullされ、プロパティが必要であるというモデル定義に違反します。を使用するのINNER JOINは良くありません。エンティティがまったく得られず、少なくとも を使用した結果と同じくらい間違ったクエリ結果が得られますLEFT OUTER JOIN

  • INNER JOINしたがって、一部Includeの s に s を使用する .NET 4 の変更は、EF 1 の SQL が間違っていたからではなく、より優れたパフォーマンスの高い SQL を作成するために行われたと思います。この変更により、一部のクエリがEF 1 の場合とは異なる結果を返すようになったという破壊的な変更が実際に導入されました。熱心な読み込み-多対多/

  • 私の理解では、これは修正されており、その理由はINNER JOIN、あまりにも多くの状況で s が EF 4 の熱心な読み込みのために導入されたためです。(おそらく、このフェーズ (ベータ版/EF 4 のリリース候補) では、クエリには 2 つINNER JOINの sが含まれていたでしょう) .) EF チームからのその問題への返信: http://connect.microsoft.com/VisualStudio/feedback/details/534675/ef4-include-method-returns-different-results-than-ef1-include (太字のハイライト私から):

    .net 4 RTM の問題を修正しています。これは意図しない重大な変更でした。インクルードによって生成されたすべての左外部結合が .Net 4 の内部結合になるような意図的な変更は行いませんでしたが、最適化では EF メタデータの制約を調べて、安全に変換できる左外部結合を変換しようとしました。制約に基づいて内部結合に。制約に基づいて推論していたコードにバグがあり、その結果、制約が意味するものよりも積極的な変換が行われました。制約に基づいて実行できることが絶対に確実な場所でのみ、左外部結合を内部結合に変換するように、最適化を縮小しました。今後、この最適化をもう少し改善できると考えています。RC や Beta 2 と比較すると、RTM の一部のクエリでより多くの左外部結合が見られるようになりますが、これらのほとんどの場合、これは正しい結果を返すために必要です。

    そのため、EF 4 の最終リリースでは、そのLEFT OUTER JOINような重大な変更を回避するために、(ベータ版/リリース候補と比較して) いくつかの s が再導入されたようです。

申し訳ありませんが、これは実際の説明ではなく、歴史的な話INNER JOINですLEFT OUTER JOIN。前述のように、クエリをこのように記述しても問題はありません。2 つINNER JOINまたは 2 つのを使用しても問題はありませんLEFT OUTER JOIN。クエリがその特定の SQL を生成する理由を正確に説明できるのは EF チームだけだと思います。

重大なパフォーマンスの問題が発生していない場合は、その SQL を気にせず (最終的に得られる結果が正しいため)、先に進むことをお勧めします。EF が作成する SQL が気に入らないと、多くの機能や変更の要求を作成したり、多くの生の SQL クエリを作成したり、EF をまったく放棄したりすることになります。

于 2011-12-16T20:14:33.510 に答える
0

これはネクロのようなものですが、今日も同じ問題が発生しました...

これに関する問題:

FROM  [dbo].[The_Peoples] AS [Extent1]
INNER JOIN [dbo].[The_Addresses] AS [Extent2] ON [Extent1].[address_id] = [Extent2].[address_id]
LEFT OUTER JOIN [dbo].[The_Work_Places] AS [Extent3] ON [Extent1].[work_place_id] = [Extent3].[work_place_id]

から来るフィルターを適用するときは[dbo].[The_Peoples]、結合にフィルターを適用するように指定するので、時間はかかりませんが、私たちが発見したこと (この問題を確認するためにクエリ プランを実行できます) は、結合を行うことです。テーブルの完全なコンテンツに、後でフィルターを適用すると、余分な時間がかかります..私たちの場合、タイムアウトをトリガーし、1〜3秒かかるはずのクエリに1分以上かかっていました

于 2013-10-23T17:56:44.500 に答える