2011-06-30 12 views
1

EF(4.1)が特定のSQLクエリを生成している理由を理解するのに少し問題があります。ここに行く:次のようにエンティティフレームワークでSQLの問題が発生しました(同じテーブルに複数の結合があります)

基本的に私は、この2つのクラス

public class Rota 
{ 
    public int RotaId { get; set; } 

    public int RotaGroupId { get; set; } 

    public virtual RotaGroup RotaGroup { get; set; } 

    public int EmployeeId { get; set; } 

    public virtual Employee Employee { get; set; } 
    ... 

public class RotaGroup 
{ 
    public int RotaGroupId { get; private set; } 

    public bool IsCurrentRota { get; set; } 

    ... 

ロタのマッピングを持っているのです。

HasKey(r => r.RotaId); 
Property(r=>r.RotaId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

HasRequired(r => r.RotaGroup).WithMany() 
          .HasForeignKey(r => r.RotaGroupId) 
          .WillCascadeOnDelete(false); 

HasRequired(r => r.Employee).WithMany() 
          .HasForeignKey(r => r.EmployeeId) 
          .WillCascadeOnDelete(false); 

...

をOK。ここで、次のLINQクエリ:

SELECT ...columns... 
FROM [dbo].[Rota] AS [Extent1] 
INNER JOIN [dbo].[RotaGroup] AS [Extent2] ON [Extent1].[RotaGroupId] = [Extent2][RotaGroupId] 
LEFT OUTER JOIN [dbo].[RotaGroup] AS [Extent3] ON [Extent1].[RotaGroupId] = [Extent3].[RotaGroupId] 
WHERE ([Extent2].[IsCurrentRota] = 1) AND ([Extent1].[MyIgluUserId] = 1 

Imはあなたが問題を見ることができます:

_context.Rotas.Include(r => r.RotaGroup) 
       .Where(r => r.EmployeeId == 1 && r.RotaGroup.IsCurrentRota) 
       .ToList(); 

には、以下のSQLを生成します。なぜなぜそれがrotaGroupに参加しているのですか(それはすべきです)、次に左外部結合を行っていますか?さらに、[Extent2](内部結合)の列は使用されません。左側の外部結合ビット([Extent3])からの列のみが使用されます。

答えて

2

[Extent2] - これはSQLのWHEREの一部です。クエリの結果は正しくなりますが、パフォーマンスはおそらく悪化します。私は、SQLサーバーが不要な左への結合を取り除くためにこれを最適化するとは思わない。

これは、EFがクエリを生成する方法です。私が理解しているように、EFはエンティティセットの使用状況を追跡しないため、2つのクエリ部分Include(r => r.RotaGroup)Where(r => r.RotaGroup.IsCurrentRota)は互いに関係しません。左結合はIncludeの結果であり、内結合はWhereの結果です。 Includeの部分がフィルタリングのサブクエリになるようにクエリを変更しようとすることはできますが、別の方法で動作するかどうかはわかりません。

+0

残念ながら、SQLはクエリを最適化していません。だから私はこれをまっすぐにしましょう、EFはIncludeのためにLEFT OUTER JOINを使用しています。INNER JOINはWhere?それはひどく奇妙です。また、RotaGroupIdはrotaの必要な外部キーです。なぜ、それはLEFT OUTER JOINを使用していますか? – Umair

+0

多分、それは私のせいです。あなたが見ているのは、私がやっている理由です(r => r.RotaGroup)です。 RotaGroupのIsCurrentRotaプロパティにアクセスします。これにより、RotaGroup.IsCurrentRotaが真であるすべてのrotasを見つけることができます。これは正しい方法ですか? – Umair

+0

これは単にクエリの生成方法です。それはここで解決できる問題ではありません。もしあなたが[connect.microsoft。com](http://connect.microsoft.com/)または[ユーザーの声]の変更要求(http://data.uservoice.com/forums/72025-ado-net-entity-framework-ef-機能の提案) - 私はすでにそれらのいくつかが存在することを期待しています。サポートチケットをお持ちの場合は、MSのサポートを依頼するか、[MSDNフォーラム](http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/threads/)でお問い合わせください。 –

1

私の場合、複数のJOINが必要でないときに同じ問題が発生します(SQLクエリは、INNERとLEFTの両方を持つ代わりに親テーブルにINNER JOINを1つだけ含むように簡単に変更できます)。親テーブルへのJOIN)。

私の問題は、複数の値(例えばchild.ParentID == 1 || child.ParentID == 2 || child.ParentID == 3)と等しいかどうかをテストすることで、 TBL1及びTBL2は、内側及びLEFT)は、SELECT文に追加のテーブルを結合されている場合:

WHERE tbl1.ParentID = 1又はtbl2.ParentID IN(2,3)

をこれらの問題の両方がで修正されています2011年6月のCTPパッケージ Entity framework CTP - June 2011

関連する問題