0

B で始まる「adrianMember」にリンクされたすべての「Places」をループする次の linq select クエリがあります。PlaceName のみを表示したいだけです。メンバーから場所へのナビゲーションの関連付けがありますが、場所からメンバーへの関連付けはありません。

using (var fdb = new FALDbContext())
{
    var adrianMember = fdb.Members.Find(1);

    foreach (string s in adrianMember.Places.Where(p=>p.PlaceName.StartsWith("B")).Select(p => p.PlaceName))
    {
        Console.WriteLine("- " + s);
    }
}

たとえば、Findを使用しないなど、さまざまなlinq構文も試しました...

var adrianMember = fdb.Members.Where(m => m.MemberId == 1).FirstOrDefault();

2 つの linq クエリを提供します。1 つはメンバーを取得し、後で関連する場所を取得します (そして、EF に遅延読み込みを実行させることを願っています) が、それでも非常に非効率な sql になります。

using (var fdb = new FALDbContext())
{
    //Need the FirstOrDefault otherwise we will return a collection (first or default will return the inner collection
    //could have multiple members with multiple places
    var members = fdb.Members.Where(m=>m.FirstName == "Bob");

    foreach (var member in members)
    {
        var places = member.Places.Where(p => p.PlaceName.StartsWith("B")).Select(p => p.PlaceName);

        foreach (var place in places)
        {
            Console.WriteLine(place);
        }
    }
}

SQL 出力はすべての行とすべての列を取得します

exec sp_executesql N'SELECT 
[Extent1].[PlaceId] AS [PlaceId], 
[Extent1].[PlaceName] AS [PlaceName], 
[Extent1].[PlaceLocation] AS [PlaceLocation], 
[Extent1].[Member_MemberId] AS [Member_MemberId]
FROM [dbo].[Places] AS [Extent1]
WHERE [Extent1].[Member_MemberId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

SQLを次のように制限する方法はありますか

SELECT PlaceName FROM Places WHERE MemberId = 1 AND PlaceName like 'B%'

私のプロジェクトでは、上記で生成された sql によってクエリが非常に遅くなる状況がいくつかあります (20 列を超えるメンバーあたり 20,000 レコード)。より多くのレコードがある場合、linq は変更を行うのに十分賢いですか?

4

2 に答える 2

2

これを試して:

using (var fdb = new FALDbContext()) 
{     
    var members = fdb.Members.Where(m=>m.FirstName == "Bob");      
    foreach (var member in members)     
    {         
        fdb.Places.Where(p => p.PlaceName.StartsWith("B") && p.MemberId == member.Id).Select(p => p.PlaceName);
        foreach (var place in places)         
        {             
            Console.WriteLine(place);         
        }     
    } 
} 

ここにも同様の質問があります

于 2012-07-07T19:14:18.753 に答える
0

この問題から1か月離れた後、もう一度見てみようと思いました...

まず、何を達成したかったのかよくわかりません!!! ただし、必要なものに対して、興味深い、より効率的な SQL クエリをいくつか見つけたようです。

私の最初のオプションは、Entry メソッドと Collection メソッドを使用して明示的な読み込みを使用することです。これにより、対応する各 Place レコードを取得するための SQL クエリが作成され、重要なことに、必要な列 (説明のみ) が射影され、行 (L で始まる Places) が制限されます。関連付けられた場所が多数ある場合、これにより多くのクエリが作成されますが、取得する場所がわからない場合は、その場でこれを実行できます。

    using (var fdb = new FALDbContext())
    {
        foreach (var member in fdb.Members)
        {
            var places = fdb.Entry(member)
                            .Collection(m => m.Places)
                            .Query()
                            .Where(p => p.PlaceName.StartsWith("L"))
                            .Select(p => p.PlaceName);

            foreach (var place in places)
            {
                Console.WriteLine(place);
            }
        }
    }

2 番目のオプションは、遅延読み込みを使用することですが、厳密に制御された LINQ to Entities のビットを指定します。

これは一度データベースに行き、必要なメンバーだけを取得し、両方のテーブルをプロジェクトして制限し、すべてを1つの素敵で効率的なSQLクエリにまとめます!

    using (var fdb = new FALDbContext())
    {
        var myList = fdb.Members
                            .Where(m => m.GenderShareWithId > 0)
                            .Select(m => new { m.MemberId, m.DisplayName, Places = m.Places.Where(p => p.PlaceName.StartsWith("L")).Select(p => p.PlaceName) });

        foreach (var item in myList)
        {
            Console.WriteLine(item.DisplayName);
            foreach (var place in item.Places)
            {
                Console.WriteLine(" - " + place);
            }
        }
    }


SELECT 
    [Extent1].[MemberId] AS [MemberId], 
    [Extent1].[DisplayName] AS [DisplayName], 
    [Extent2].[PlaceName] AS [PlaceName]
FROM  [dbo].[Members] AS [Extent1]
LEFT OUTER JOIN [dbo].[Places] AS [Extent2] 
    ON ([Extent1].[MemberId] = [Extent2].[Member_MemberId]) AND ([Extent2].[PlaceName] LIKE N'L%')
WHERE [Extent1].[GenderShareWithId] > 0
于 2012-08-07T00:05:57.603 に答える