2016-07-28 1 views
-3

IQueryableを返す関数で2つのテーブル結合があるとしますが、その出力は2つのどちらでもない名前付きの型ですテーブル:フィールドが選択された出力にないときにWhere()をIQueryableに追加できますか

var qry = from p in Persons 
      join h in Hobbies on p.PersonId equals h.PersonId 
      select new OutputType 
      { 
       Name = p.FirstName, 
       Hobby = h.HobbyName 
      } 

return qry 

のは、今私はこれが返されたクエリを取るなど何かやってみたかったとしましょう:あなたはのIQueryableがタイプOUTPUTTYPEであるため、これは問題ですので、私ができる見ることができるように

var newQuery = qry.Where(p=>p.Age > 18) 

をAgeTypeをOutputTypeに追加しない限り、人の年齢にどこに追加してください。

IQueryable式ツリーに「侵入」してラムダを追加して、そこに指定されたソースコレクションをクエリし、Where句を追加しますか?または、最終的に投影することに無関心であっても、WhereフィールドをOutputTypeに追加する必要がありますか?

+3

私はあなたが本当にしたい場合、これを行うための方法を見つけることができ疑いますが、本当にそれはあなたのデザインが欠陥があるだけの兆候だ、とあなたはあなたが前にフィルタリングをやっているようにあなたのコードを構築する必要がありますシーケンスを投影する。 – Servy

+0

少し改造して、 'Persons'の値を渡すこともできます。ですから、 'Persons'の代わりに' Persons.Where(p => p.Age> 18) ' –

+0

に渡します。私が与えた例はちょうどその例でした。私はちょうど概念ではなく、使用法を示していた。実際のケースは、既存の従来のOracleデータベースの上に4テーブル・ジョインです。同じ(大)クエリの3つの異なるバリエーションがあり、異なるテーブルの非投影値のWhere句のみが異なります。私は複数の大規模なLINQクエリを維持していないので、コードの冗長性を減らそうとしています。以下の最初の答えは、私がフィールドを早期に追加し、最終的にそれを投影しないためにペナルティを課せられないという点で非常に役立ちます。唯一のネガティブは、複数の新しいタイプを作ることです。 –

答えて

1

バックトラックしようとするよりも後で表示を絞り込む方が簡単です。ここでは、再利用のためにメソッドをレイヤ化して、すてきなSQLを吐き出すように、どのようにして削除したかの例を取り上げます。

private IQueryable<Part> GetParts_Base() 
{ 
    //Proprietary. Replace with your own. 
    var context = ContextManager.GetDbContext(); 

    var query = from c in context.Component 
       where c.Active 
       //kind of pointless to select into a new object without a join, but w/e 
       select new Part() 
       { 
        PartNumber = c.ComponentNumber, 
        Description = c.ComponentDescription, 
        Cost = c.ComponentCost, 
        Price = c.ComponentPrice 
       }; 

    return query; 
} 

//Exclude cost from this view 
public IEnumerable<Part_PublicView> GetParts_PublicView(decimal maxPrice) 
{ 
    var query = GetParts_Base(); 

    var results = from p in query 
        where p.Cost < maxPrice 
        select new Part_PublicView() 
        { 
         PartNumber = p.PartNumber, 
         Description = p.Description, 
         Price = p.Price 
        }; 

    return results; 
} 

public class Part_PublicView 
{ 
    public string PartNumber { get; set; } 
    public string Description { get; set; } 
    public decimal Price { get; set; } 
} 

private class Part : Part_PublicView 
{ 
    public decimal Cost { get; set; } 
} 

Linq-to-entityは、余分な列を早期に選択しても、あなたにペナルティを課すことはありません。ご覧のように、sqlには制約内のCost列が含まれていますが、selectでは選択できません。

SELECT 
    1 AS [C1], 
    [Extent1].[ComponentNumber] AS [ComponentNumber], 
    [Extent1].[ComponentDescription] AS [ComponentDescription], 
    [Extent1].[ComponentPrice] AS [ComponentPrice] 
FROM [dbo].[Component] AS [Extent1] 
WHERE [Extent1].[ComponentCost] < @p__linq__0 
+0

唯一のネガティブは、各レイヤーでこれらの名前付きタイプをすべて作成することですが、あなたが与えた答えは非常に堅実です。実際には、IQueryableのビットがメソッドの戻り値にアクセスするのが非常に難しいことが残念ですが、これが当てはまると思われます。ありがとう! –

関連する問題