2013-08-01 99 views
1

我試圖用一個linq語句來解決某些問題,我不知道是否可以這樣做。 我有一個表叫的價格,與此字段:使用linq標準合併兩個表

pkey: int 
region: int? 
product_type: int 
product_size: int 
price: double 
desc: string 

獨特的關鍵是:產品類型+ product_size

我想這樣做,返回所有行的查詢WHERE區域== 17 (這是我的第一組行) 並且想要添加區域爲空的所有行 (這是我的第二組行) 但是 如果在兩個集合中存在具有相同product_type和product_size的行,我想在最終結果中只是第一組的一排。

實施例:

pkey | region | product_type | product_size | price | desc 

1, null, 20,   7,    2.70, salad1  
2, null, 20,   3,    2.50, salad7  
3, 17,  20,   7,    1.90, saladspecial  
4, 17,  20,   5,    2.20, other 

我想LINQ查詢返回該:

2, null, 20,   3,    2.50, salad7  
3, 17,  20,   7,    1.90, saladspecial  
4, 17,  20,   5,    2.20, other 

(請注意,行與p鍵1被丟棄,因爲與p鍵3中的行具有相同的產品類型和product_size )

var query1 = from p in PRICES where p.region == 17  
      select p; 

var query2 = from p in PRICES where p.region is null  
      select p; 

問題:

  1. 如何連接query1和query2以獲得預期的輸出?

  2. 它可以完成只有1個查詢?

回答

2

下面的查詢只選擇價格與區域17null,通過唯一的密鑰{ p.product_type, p.product_size }組他們。然後它檢查組是否包含至少一個區域17的價格。如果是,那麼我們從組中選擇該區域的所有價格(並且跳過null區域的價格)。否則,我們返回整個組(它只有零位區域):

var query = from p in PRICES.Where(x => x.region == 17 || x.region == null) 
      group p by new { p.product_type, p.product_size } into g 
      from pp in g.Any(x => x.region == 17) ? 
         g.Where(x => x.region == 17) : g 
      select pp; 

輸入:

1 null 20 7 2.7 salad1  // goes to group {20,7} with region 17 price 
2 null 20 3 2.5 salad7  // goes to group {20,3} without region 17 prices 
3 17 20 7 1.9 saladspecial // goes to group {20,7} 
4 17 20 5 2.2 other  // goes to group {20,5} 

輸出:以上

2 null 20 3 2.5 salad7 
3 17 20 7 1.9 saladspecial 
4 17 20 5 2.2 other 

編輯查詢工作正常,在內存(對象即LINQ到對象),但LINQ到Entitis不是那麼強大 - 它不支持嵌套查詢。因此,對於實體框架,您將需要兩個查詢 - 一個與null區域,不具有區域17價格在一組,二來獲取價格 - 從區域17價格:

var pricesWithoutRegion = 
      db.PRICES.Where(p => p.region == 17 || p.region == null) 
       .GroupBy(p => new { p.product_type, p.product_size }) 
       .Where(g => !g.Any(p => p.region == 17)) 
       .SelectMany(g => g); 

var query = db.PRICES.Where(p => p.region == 17).Concat(pricesWithoutRegion); 

其實EF執行兩個子 - 向服務器查詢一個UNION查詢。下面的SQL將生成(我刪除遞減價格列以適合屏幕):

SELECT [UnionAll1].[pkey] AS [C1], 
     [UnionAll1].[region] AS [C2], 
     [UnionAll1].[product_type] AS [C3], 
     [UnionAll1].[product_size] AS [C4] 
FROM (SELECT [Extent1].[pkey] AS [pkey], 
      [Extent1].[region] AS [region], 
      [Extent1].[product_type] AS [product_type], 
      [Extent1].[product_size] AS [product_size] 
     FROM [dbo].[Prices] AS [Extent1] WHERE 17 = [Extent1].[region] 
UNION ALL 
    SELECT [Extent4].[pkey] AS [pkey], 
      [Extent4].[region] AS [region], 
      [Extent4].[product_type] AS [product_type], 
      [Extent4].[product_size] AS [product_size] 
    FROM (SELECT DISTINCT [Extent2].[product_type] AS [product_type], 
         [Extent2].[product_size] AS [product_size] 
     FROM [dbo].[Prices] AS [Extent2] 
     WHERE ([Extent2].[region] = 17 OR [Extent2].[region] IS NULL) AND 
       (NOT EXISTS 
       (SELECT 1 AS [C1] FROM [dbo].[Prices] AS [Extent3] 
       WHERE ([Extent3].[region] = 17 OR [Extent3].[region] IS NULL) 
         AND ([Extent2].[product_type] = [Extent3].[product_type]) 
         AND ([Extent2].[product_size] = [Extent3].[product_size]) 
         AND (17 = [Extent3].[region]) 
       ))) AS [Distinct1] 
    INNER JOIN [dbo].[Prices] AS [Extent4] 
     ON ([Extent4].[region] = 17 OR [Extent4].[region] IS NULL) 
      AND ([Distinct1].[product_type] = [Extent4].[product_type]) 
      AND ([Distinct1].[product_size] = [Extent4].[product_size])) 
    AS [UnionAll1] 

BTW這讓我吃驚的是GroupBy被譯成內的條件加入。

+1

你山石人,它的工作奇妙 – DiegoGalo

+0

有我與您的查詢的異常:「一個有效的與resultType可能不能從指定的'Then'表達式的ResultType中推斷出來。「這是爲什麼發生? – DiegoGalo

+2

@DiegoGalo我已經測試了'lazyberezovsky'的查詢,它工作正常。 'expression'的風格使得這個查詢比'method'風格更簡潔。 –

1

我覺得你應該去1個查詢2個查詢,我們不得不重複了一句:

//for 2 queries 
var query = query1.Union(query2.Except(query2.Where(x=>query1.Any(y=>x.product_type==y.product_type&&x.product_size==y.product_size)))) 
        .OrderBy(x=>x.pkey); 

//for 1 query 
//the class/type to make the group key 
public class GroupKey 
{ 
     public int ProductType { get; set; } 
     public int ProductSize { get; set; } 
     public override bool Equals(object obj) 
     { 
      GroupKey gk = obj as GroupKey; 
      return ProductType == gk.ProductType && ProductSize == gk.ProductSize; 
     } 
     public override int GetHashCode() 
     { 
      return ProductSize^ProductType; 
     } 
} 
//------- 
var query = list.Where(x => x.region == 17 || x.region == null) 
       .GroupBy(x => new GroupKey{ProductType = x.product_type, ProductSize = x.product_size }) 
       .SelectMany<IGrouping<GroupKey,Price>,Price,Price>(x => x.Where(k => x.Count(y => y.region == 17) == 0 || k.region == 17), (x,g) => g) 
       .OrderBy(x=>x.pkey); 
+0

不錯的使用SelectMany子句,您的解決方案工作得非常好 – DiegoGalo

+0

錯誤方法'System.Linq.Enumerable.SelectMany 的類型參數(System.Collections.Generic.IEnumerable ,System.Func >,System.Func )'不能從使用情況中推斷出來。嘗試明確指定類型參數。 – DiegoGalo

+0

@DiegoGalo我更新了我的答案,所有2種方式都經過測試。 –