[英]Linq + MoreLinq how to aggregate one result prop to list?
I have a problem with query, please take a look. 我的查询有问题,请看一看。 My aim is:
我的目标是:
Products
with one Image
. Products
带一张Image
。 Products
has Values
which are some additional information aboute the product like specification etc. Products
具有Values
,这些Values
是有关产品的一些其他信息,例如规格等。 Image
and Values
can be null
Image
和Values
可以为null
Products
with Image
and Values
Products
与Image
和Values
Values
I need only Ids
so its ok to get List<int> of Values
Values
我仅需要Ids
因此可以获取List<int> of Values
ProductValues
and ImageObjects
are connecting table for relationship --> Products
can have many ProductValues
also Products
can have many ImageObjects
but can have one Image
ProductValues
和ImageObjects
连接关系表-> Products
可以具有许多ProductValues
Products
也可以具有许多ImageObjects
但可以具有一个Image
DistinctBy
is from more linq
DistinctBy
是从more linq
Question I don't know how to aggregate Values
in correct way to return list of Values
per Product
问题我不知道如何以正确的方式汇总
Values
以返回每个Product
的Values
列表
PS I'm also using more linq PS我也使用更多的LINQ
var q1 = (from p in Products
join pv in ProductValues on p.ProductId equals pv.ProductId into ljpv
from pv in ljpv.DefaultIfEmpty()
select new
{
ProductId = p.ProductId,
Description = p.Description,
Name = p.Name,
Price = p.Price,
Quantity = p.Quantity,
Type = p.Type,
Values = (from v in ValueTypes
where v.ValueId == pv.ValueId
select new {
ValueId = v.ValueId
}).ToList(),
ImageObjects = (from io in ImageObjects
where io.ProductId == p.ProductId && io.IsDefault == true
select new
{
Image = io.Image,
IsDefault = io.IsDefault,
ProductId = io.ProductId
})
.ToList()
})
.DistinctBy(x=>x.Name)
.OrderBy(x=>x.Name);
q1.Dump();
Answer Values = (from tmp in ljpv select new { ValueId = tmp.ValueId}),
答案
Values = (from tmp in ljpv select new { ValueId = tmp.ValueId}),
I know that this is not place to answer, but meaby someone will have any addvices to my code or meaby it can be done more clear or faster. 我知道这不是解决问题的地方,但是meaby可以对我的代码或meaby有所帮助,可以更清楚或更快速地完成。 I've been wondering how to do this query for a long time, but as I wrote to you, I got a dazzle:)
很长一段时间以来,我一直在想如何执行此查询,但是当我写信给您时,我很眼花:乱:)
after @Harald Coppoolse
answer - the code is more faster! @Harald Coppoolse
回答之后-代码更快!
return context.Product.GroupJoin(
context.ProductValue,
context.ImageObject.Include(x => x.Image),
p => p.ProductId,
pv => pv.ProductId,
io => io.ProductId,
(p, pv, io) => new ProductModel
{
ProductId = p.ProductId,
Name = p.Name,
Price = p.Price,
ProductValue = pv
.Select(npv => new ProductValueModel
{
ProductId = npv.ProductId,
}).ToList(),
ImageObject = io
.Select(nio => new ImageObjectModel
{
Image = nio.Image.DtoToModel(),
IsDefault = nio.IsDefault,
ProductId = nio.ProductId
}).ToList(),
});
So you have a table of Products
and a table of ProductValues
with a one-to-many relation: every Product
has zero or more ProductValues
and every ProductValue
belongs to exactly one Product
, namely the Product
that the foreign key ProductId
points to. 所以,你有一个表
Products
和表ProductValues
有一个一对多的关系:每一个Product
都有零个或多个ProductValues
每ProductValue
属于一个Product
,即Product
外键ProductId
点。
You want (several properties of) all Products
, each Product
with its ProductValues
. 您需要所有
Products
(的几个属性),每个Product
及其ProductValues
。 After that you DistinctBy
and OrderBy
, but that is not your problem. 此后,您就可以使用
DistinctBy
和OrderBy
,但这不是您的问题。
Whenever you want "items with their sub-items", like "Schools with their Students", "Customers with their Orders", "Orders with their Order lines", consider using Enumerable.GroupJoin 每当您需要“带子项目的项目”(例如“带学生的学校”,“带订单的客户”,“带订单行的订单”)时,请考虑使用Enumerable.GroupJoin
GroupJoin is in fact a Left Outer Join, followed by a GroupBy. 实际上,GroupJoin是左外部联接,其后是GroupBy。
var productsWithTheirProductValues = products.GroupJoin( // GroupJoin Products
productValues, // with ProductValues
product => product.ProductId, // from every Product take the ProductId
productValue => productValue.ProductId, // from every ProductValue take the foreign key
// ResultSelector: take the product with its zero or more matching ProductValues
// to make a new object:
(product, productValuesOfThisProduct) => new
{
// Select only the product properties you plan to use:
Id = product.Id,
Name = product.Name,
Price = product.Price,
...
ProductValues = productValuesOfThisProduct
// only if you don't want all ProductValues of this product:
.Where(productValue => ...)
.Select(productValue => new
{
// again select only the properties you plan to use
Id = productValue.Id,
...
// not needed: the foreign key, you already know the value
// ProductId = productValue.ProductId,
})
.ToList(),
});
In your case, you don't want to GroupJoin two sequences, but three sequences. 在您的情况下,您不想GroupJoin两个序列,而是三个序列。 You'l need to do an extra GroupJoin:
您需要做一个额外的GroupJoin:
var result = products.GroupJoin(productValues,
product => product.ProductId,
productValue => productValue.ProductId,
// ResultSelector: remember the product and all its productValues
(product, productValuesOfThisProduct) => new
{
Product = product,
ProductValues = productValuesOfThisProduct,
})
// now do the 2nd join:
.GroupJoin(imageObjects,
firstJoinResult => firstJoinResult.Product.ProductId,
imageObject => imageObject.ProductId,
// result selector:
(firstJoinResult, imageObjectsOfThisProduct) => new
{
Product = firstJoinResult.Product,
ProductValues = firstJoinResult.ProductValues,
ImageObjects = imageObjectsOfThisProduct,
})
// take each element of this group join result and select the items that you want
.Select(joinResult => new
{
ProductId = joinResult.Product.ProductId,
Price = joinResult.Product.Price,
...
ProductValues = joinResult.ProductValues.Select(productValue => new
{
...
})
.ToList(),
ImageObjects = joinResult.ImageObjects.Select(imageObject => new
{
...
})
.ToList(),
});
This looks horrible. 这看起来太可怕了。 So if you have to do a GroupJoin with three tables more often, consider to create a GroupJoin for three tables:
因此,如果您必须更频繁地使用三个表进行GroupJoin,请考虑为三个表创建一个GroupJoin:
static IEnumerable<TResult> GroupJoin<T1, T2, T3, TKey, TResult>(
this IEnumerable<T1> source1, IEnumerable<T2> source2, IEnumerable<T3> source3,
Func<T1, TKey> key1Selector,
Func<T2, TKey> key2Selector,
Func<T3, TKey> key3Selector,
Func<T1, IEnumerable<T2>, IEnumerable<T3>, TResult> resultSelector)
{
// put all source2 and source3 elements in lookuptables, using the keyselector
var lookup2 = source2.ToLookup(item => key2Selector(item));
var lookup3 = source3.ToLookup(item => key3Selector(item));
// now for every source1 item, get all source2 and source3 items with the same key
// and create the result:
foreach (var item1 in source1)
{
TKey key1 = key1Selector(item1);
IEnumerable<T2> items2 = lookup2[key1];
IEnumerable<T3> items3 = lookup3[key1];
// returns empty collection if no items with this key
TResult result = resultSelector(item1, items2, items3);
yield return result;
}
}
usage: 用法:
var result = products.GroupJoin(productValues, imageObjects,
product => product.ProductId,
productValue => productValue.ProductId,
imageObject => imageObject.ProductId,
(product, productValues, imageObjects) => new
{
ProductId = product.ProductId,
...
ProductValues = productValues.Select(productValue => new
{
...
}),
ImageObjects = imageObjects.Select(imageObject => new
{
...
}),
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.