使用代码可以更好地解释我想要的内容。我有这个问题:
var items = context.Items.GroupBy(g => new {g.Name, g.Model})
.Where(/*...*/)
.Select(i => new ItemModel{
Name=g.Key.Name,
SerialNumber = g.FirstOrDefault().SerialNumber //<-- here
});
是否有更好的方法来获取密钥中未使用的序列号或其他属性?我能想到的唯一方法是使用FirstOrDefault。
答案 0 :(得分:2)
为什么不通过您声明的匿名类型将序列号作为密钥的一部分包含在内:
var items = context.Items.GroupBy(g => new {g.Name, g.Model, g.SerialNumber })
.Where(/*...*/)
.Select(i => new ItemModel {
Name=g.Key.Name,
SerialNumber = g.FirstOrDefault().SerialNumber //<-- here
});
或者,或者,让你的对象成为关键:
var items = context.Items.Where(...).GroupBy(g => g)
.Select(i => new ItemModel {...});
有时可以更容易理解查询语法(这里,我将Item
对象作为键的一部分进行了预测):
var items = from i in context.Items
group i by new { Serial = g.Serialnumber, Item = g } into gi
where /* gi.Key.Item.GetType() == typeof(context.Items[0]) */
select new ItemModel {
Name = gi.Key.Name,
SerialNumber = gi.Key.Serial
/*...*/
};
编辑:您可以尝试在投影后进行分组:
var items = context.Items.Where(/*...*/).Select(i => new ItemModel { /*...*/})
.GroupBy(g => new { g.Name, g.Model });
你得到了一个
IGrouping<AnonymousType``1, IEnumerable<ItemModel>>
来自此group by
作为键,您的ItemModels作为分组集合。
答案 1 :(得分:1)
我强烈反对你正在做的事情。序列号是任意选择的,因为您的查询中没有排序。如果您确切地指定选择哪个序列号,如果查询以不同于“上次”的顺序返回项目,则会更好。
话虽如此,我认为投影分组并选择您需要的字段并获得第一个结果会更清晰。它们都具有相同的键值,因此保持不变,然后您可以添加所需的任何其他字段。
var items = context.Items.GroupBy(i => new { i.Name, i.Model })
.Where(/*...*/)
.Select(g =>
g.OrderBy(i => i.Name).Select(i => new ItemModel
{
Name = i.Name,
SerialNumber = i.SerialNumber,
}).FirstOrDefault()
);
答案 2 :(得分:0)
由于您需要所有数据,因此需要将所有组数据存储到您的值中(在KeyValuePair中)。
我没有在我面前的确切语法,但它看起来像:
/* ... */
.Select(g => new {
Key = g.key,
Values = g
});
之后,您可以遍历Key
以获取Name
群组。在该循环内部,在Values
中包含一个循环以获取ItemModel
(我猜这是包含1个元素的对象)。
看起来像是:
foreach (var g in items)
{
Console.WriteLine("List of SerialNumber in {0} group", g.Key);
foreach (var i in g.Values)
{
Console.WriteLine(i.SerialNumber);
}
}
希望这有帮助!
您可能需要查看Linq 101 samples以获取有关不同查询的帮助。
答案 3 :(得分:0)
如果序列号对于名称和型号是唯一的,则应将其按对象包含在组中。
如果不是,那么你有一个每个名称和型号的连续出版物列表,选择firstordefault可能是完全错误的,也就是说,我认为没有你想要的情况。