0

Entity Framework を使用した大規模なシステムに取り組んでいます。個人的には、LINQ / ESQL クエリを記述するためのメソッド ベースの構文が気に入っています。

しかし、次の結合クエリを適切に作成する方法がわかりません。

次のエンティティ クラスと DbContext リポジトリがあるとします。

public class A
{
    [Key]
    public int ID{get;set;}
    public virtual ICollection<B> BCollection { get; set; }
}
public class B
{
    [Key]
    public int ID { get; set; }
    public virtual A A { get; set; }
    public virtual ICollection<C> CCollection { get; set; }
    public virtual ICollection<D> DCollection { get; set; }
}
public class C
{
    [Key]
    public int ID { get; set; }
    public virtual B B { get; set; }
}
public class D
{
    [Key]
    public int ID { get; set; }
    public virtual B B { get; set; }
}
public class Entities : DbContext
{
    public DbSet<A> SetA { get; set; }
    public DbSet<B> SetB { get; set; }
    public DbSet<C> SetC { get; set; }
    public DbSet<D> SetD { get; set; }
}

ここで、「全体」ツリーを取得したいと思います。クラス A のすべてのアイテムと、クラス B のアイテムが付属し、クラス B の各アイテムにはクラス C と D のアイテムが装備されています。

私はこのクエリでそれを行うことができます:

var x = db.SetA
            .Include(a => a.BCollection.Select(b => b.CCollection))
            .Include(a => a.BCollection.Select(b => b.DCollection))
            .ToList();

しかし、これはもっと簡単にできると思いますよね?

注意: 遅延読み込みを使用したくないので、ツリー全体を積極的に読み込みたいと思います。

編集:

これは 1 つの問題に関する質問ではありません。私の質問はアプローチに関するものです。上記のようにクエリを作成すると、EF は非常に巨大なクエリを生成します。

 SELECT [Project3].[ID] AS [ID],
   [Project3].[C9] AS [C1],
   [Project3].[C2] AS [C2],
   [Project3].[C3] AS [C3],
   [Project3].[C4] AS [C4],
   [Project3].[C1] AS [C5],
   [Project3].[C5] AS [C6],
   [Project3].[C6] AS [C7],
   [Project3].[C7] AS [C8],
   [Project3].[C8] AS [C9]
FROM   (SELECT [Extent1].[ID]     AS [ID],
           [UnionAll1].[C1]   AS [C1],
           [UnionAll1].[ID]   AS [C2],
           [UnionAll1].[ID1]  AS [C3],
           [UnionAll1].[A_ID] AS [C4],
           [UnionAll1].[ID2]  AS [C5],
           [UnionAll1].[B_ID] AS [C6],
           [UnionAll1].[C2]   AS [C7],
           [UnionAll1].[C3]   AS [C8],
           CASE
             WHEN ([UnionAll1].[ID] IS NULL) THEN CAST(NULL AS int)
             ELSE 1
           END                AS [C9]
    FROM   [dbo].[A] AS [Extent1]
           OUTER APPLY (SELECT CASE
                                 WHEN ([Extent3].[ID] IS NULL) THEN CAST(NULL AS int)
                                 ELSE 1
                               END               AS [C1],
                               [Extent2].[ID]    AS [ID],
                               [Extent2].[ID]    AS [ID1],
                               [Extent2].[A_ID]  AS [A_ID],
                               [Extent3].[ID]    AS [ID2],
                               [Extent3].[B_ID]  AS [B_ID],
                               CAST(NULL AS int) AS [C2],
                               CAST(NULL AS int) AS [C3]
                        FROM   [dbo].[B] AS [Extent2]
                               LEFT OUTER JOIN [dbo].[C] AS [Extent3]
                                 ON [Extent2].[ID] = [Extent3].[B_ID]
                        WHERE  [Extent1].[ID] = [Extent2].[A_ID]
                        UNION ALL


                        SELECT 2                 AS [C1],
                               [Extent4].[ID]    AS [ID],
                               [Extent4].[ID]    AS [ID1],
                               [Extent4].[A_ID]  AS [A_ID],
                               CAST(NULL AS int) AS [C2],
                               CAST(NULL AS int) AS [C3],
                               [Extent5].[ID]    AS [ID2],
                               [Extent5].[B_ID]  AS [B_ID]
                        FROM   [dbo].[B] AS [Extent4]
                               INNER JOIN [dbo].[D] AS [Extent5]
                                 ON [Extent4].[ID] = [Extent5].[B_ID]
                        WHERE  [Extent1].[ID] = [Extent4].[A_ID]) AS [UnionAll1]) AS [Project3]
ORDER  BY [Project3].[ID] ASC,
      [Project3].[C9] ASC,
      [Project3].[C3] ASC,
      [Project3].[C1] ASC

しかし、私が実際に自分で書くのは次のようなものです。

SELECT     *
FROM         D RIGHT OUTER JOIN
                  B ON D.B_ID = B.ID LEFT OUTER JOIN
                  C ON B.ID = C.B_ID RIGHT OUTER JOIN
                  A ON B.A_ID = A.ID

これが私の質問を明確にするのに役立つことを願っています。ポイントは、Entity Framework でより効率的なクエリを生成するにはどうすればよいかということです。

4

1 に答える 1

1

次の LINQ は、探している「メガ」クエリを生成すると思います。

    var query =
        db.SetA
            .Join(db.SetB, a => a, b => b.A, (a, b) => new
                                                           {
                                                               A = a,
                                                               B = b
                                                           })
            .Join(db.SetC, ab => ab.B, c => c.B, (ab, c) => new
                                                                {
                                                                    A = ab.A,
                                                                    B = ab.B,
                                                                    C = c
                                                                })
            .Join(db.SetD, abc => abc.B, d => d.B, (abc, d) => new
                                                                   {
                                                                       A = abc.A,
                                                                       B = abc.B,
                                                                       C = abc.C,
                                                                       D = d
                                                                   });

    foreach (var abcd in query)
    {
        Console.WriteLine("{0}-{1}-{2}-{3}", abcd.A.ID, abcd.B.ID, abcd.C.ID, abcd.D.ID);
    }
于 2012-06-12T10:10:30.780 に答える