2011-09-09 8 views
14

私は完全にSQLに変換できるクエリを持っています。不明な理由により、LINQは最後のSelect()を(データベースではなく).NETで実行するように決定します。これによりデータベースに対して追加のSQLクエリが(各アイテムごとに)実行されます。データベース内のクエリ全体をLINQでSQLに評価させるにはどうすればよいですか?

は実は、私は、SQLに完全な翻訳を強制する「奇妙な」方法を見つけた:

私は(これは期待通りまだ動作しません、本当に簡易版です)クエリを持っている:

MainCategories.Select(e => new 
{ 
    PlacementId = e.CatalogPlacementId, 
    Translation = Translations.Select(t => new 
    { 
     Name = t.Name, 
     // ... 
    }).FirstOrDefault() 
}) 

01:私は別の Select()だけコピーすべてのメンバーを追加する場合は、しかし、

SELECT [t0].[CatalogPlacementId] AS [PlacementId] 
FROM [dbo].[MainCategories] AS [t0] 

SELECT TOP (1) [t0].[Name] 
FROM [dbo].[Translations] AS [t0] 

SELECT TOP (1) [t0].[Name] 
FROM [dbo].[Translations] AS [t0] 

... 

:それは意志

は、SQLクエリの多くを生成し、

.Select(e => new 
{ 
    PlacementId = e.PlacementId, 
    Translation = new 
    { 
     Name = e.Translation.Name, 
     // ... 
    } 
}) 

これは、単一のSQL文にコンパイルされます:

SELECT [t0].[CatalogPlacementId] AS [PlacementId], (
    SELECT [t2].[Name] 
    FROM (
     SELECT TOP (1) [t1].[Name] 
     FROM [dbo].[Translations] AS [t1] 
     ) AS [t2] 
    ) AS [Name] 
FROM [dbo].[MainCategories] AS [t0] 

任意の手掛かりなぜですか? LINQ to SQLをより一般的に単一のクエリを生成するように強制する方法(2回目のコピーなし)Select()

注:私はそれを本当に簡単にするように更新しました。

PS:唯一のアイデアは、同様のパターン(別のSelect()を追加する)で後処理/変換を行うことです。

+2

MyQuery()を表示してください。 –

答えて

6

MyQuerySingleOrDefaultを呼び出すと、結果がクライアントにロードされている時点でクエリが実行されます。

SingleOrDefaultはIEnumerable<T>を返します。これはもはやIQueryable<T>ではありません。この時点で、クライアント上ですべての処理を行います。これでSQL合成は実行できなくなります。

+0

別の 'Select()'を追加すると、なぜ動作するのですか? 'SingleOrDefault'は別のクエリの中に入れ子になっています。 –

+0

それについて100%確実ではありません。 SingleOrDefaultは、結果セットに単一のレコードがあるかどうかを判断するためにクエリを評価する必要があります。最初のケースでは、ToArrayはMainCategoriesを繰り返し処理し、Translationsピース(各カテゴリのクエリを繰り返し処理するようにネストされています)に対してSingleOrDefaultを実行します。 SELECTの3番目のレイヤーを追加すると1つのクエリが送信されるかどうかはどのように分かりますか? –

+0

IQueryableを強制的に強制することについての私の追加ノートを参照してください。をIEnumerable に追加してください。 –

1

何が起こっているのか完全にはわかりませんが、あなたがこのクエリをかなり奇妙に書いた方法を見つけることができます。私はこのようにそれを書き、これは動作します疑うでしょう:

 var q = from e in MainCategories 
       let t = Translations.Where(t => t.Name == "MainCategory" 
        && t.RowKey == e.Id 
        && t.Language.Code == "en-US").SingleOrDefault() 
       select new TranslatedEntity<Category> 
          { 
           Entity = e, 
           Translation = new TranslationDef 
               { 
                Language = t.Language.Code, 
                Name = t.Name, 
                Xml = t.Xml 
               } 
          }; 

私は常にあなたのターゲット・タイプにselect一部(投影からfrom部分(データソースの選択)を分離しようと、私はそれも簡単に見つけます。

MainCategories.Select(e => new 
{ 
    PlacementId = e.CatalogPlacementId, 
    TranslationName = Translations.FirstOrDefault().Name, 
}) 

限り私は承知しているとして、それが原因です:望ましい結果を得るために、次のように/理解読んで、それは一般的に、ほとんどのLINQプロバイダと良い作品

+0

はい、私のクエリは手書きではなく、むしろ生成されています。 (私はまだ実際には動作していない単純に単純な例を投稿しました:) –

1

するクエリを書くことができますLINQがクエリをどのように投影するかkは入れ子になっているSelectを見ると、IIRCはSQLのサブクエリから複数の戻り列を使うことができないので、LINQはこれを次のように変更するため、本質的に必要なものを複数のサブクエリに投影しません。行ごとのクエリです。 FirstOrDefaultは、列アクセサーを使用しているため、SQLで何が起きるか直接的に解釈されるため、LINQ-SQLはサブクエリを作成できます。

第2のSelectは、私が上に書いたのと同様のクエリを投げなければなりません。リフレクターを掘らずに確認するのは難しいでしょう。一般に、多くの列を選択する必要がある場合は、

from e in MainCategories 
let translation = Translations.FirstOrDefault() 
select new 
{ 
    PlacementId = e.CatalogPlacementId, 
    Translation = new { 
     translation.Name, 
    } 
}) 
+0

元のクエリははるかに複雑です。手書きではなく、いくつかの機能によって生成されます。私は単にクエリを書き換えることはできません。私ができることは、 'let 'が実際にやっている別の' Select() 'を追加することだけです。 –

+1

パフォーマンスの悪いSQLを生成していて、他の呼び出し元がアプリケーションに大きなボトルネックを引き起こす可能性があるため、問題のクエリを書き直しませんか?出力は同じで、ずっと良い入力です。鉱山とあなたの質問との間には微妙な違いがあります。 – Mig

+0

私は、結果のクエリは手書きではなく、LINQ式ツリー変換関数で生成されたものであることを述べましたが、別の 'Select()'クエリを追加したり、LINQ式ツリーを変換したりしています。 –

関連する問題