C# 使用linq标准合并两个表
我试图用一句linq来解决一些问题,我不知道是否有可能做到这一点。 我有一个名为PRICES的表,其中包含以下字段:C# 使用linq标准合并两个表,c#,linq,C#,Linq,我试图用一句linq来解决一些问题,我不知道是否有可能做到这一点。 我有一个名为PRICES的表,其中包含以下字段: pkey: int region: int? product_type: int product_size: int price: double desc: string 唯一的关键是:产品类型+产品尺寸 var query1 = from p in PRICES where p.region == 17 select p; va
pkey: int
region: int?
product_type: int
product_size: int
price: double
desc: string
唯一的关键是:产品类型+产品尺寸
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;
我想做一个查询,返回region==17的所有行
这是我的第一组行
并希望添加区域为空的所有行
这是我的第二组行
但是
如果两个集合中都有具有相同product_类型和product_大小的行,则我希望在最终结果中只包含第一个集合的行
例如:
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
请注意,pkey为1的行被丢弃,因为pkey为3的行具有相同的产品类型和产品大小
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;
问题:
如何连接query1和query2以获得预期的输出
只需一个查询就可以完成吗
以下查询仅选择区域为17或空的价格,按唯一键{p.product_type,p.product_size}对其进行分组。然后检查组是否包含至少一个区域17的价格。如果是,则我们从组中选择此区域的所有价格,并跳过带有空区域的价格。否则,我们返回整个组,因为它只有空区域:
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没有那么强大-它不支持嵌套查询。因此,对于Entity Framework,您将需要两个查询-一个是获取带有空区域的价格,该区域在组中没有区域17价格,另一个是来自区域17的价格:
实际上,EF在对服务器的一个联合查询中执行两个子查询。在删除描述和价格列以适应屏幕时,将生成以下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]
顺便说一句,GroupBy被翻译成带条件的内部联接,这让我感到惊讶。我认为您应该进行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);
SelectMany子句使用得很好,您的解决方案工作得很好错误42无法从用法推断方法“System.Linq.Enumerable.SelectManySystem.Collections.Generic.IEnumerable,System.Func,System.Func”的类型参数。尝试显式指定类型参数。您的查询出现异常:无法从指定的“Then”表达式的ResultType推断出有效的ResultType。为什么会发生这种情况?@Diegagalo我已经测试了lazyberezovsky的查询,结果正常。表达式样式使此查询比方法样式更简洁。@lazyberezovsky如何知道与LINQ查询对应的SQL查询?有工具吗?谢谢@KingKing在本例中,我使用了SQL Profiler,您可以在“所有程序”>“SQL Server”>“性能工具”中找到它。另一个不错的选择是,您可以从NuGetGreat work guys获得它的试用版。还有另一种了解SQL查询的方法。只需放置一个断点,并用鼠标指向pricesWithoutRegion,您将看到IQueryable和SQL查询。