3

我想要用代码更好地解释。我有这个查询:

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。

4

4 回答 4

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 作为分组集合。

于 2013-04-17T15:26:19.980 回答
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()
    );
于 2013-04-17T19:03:44.073 回答
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 示例以获取有关不同查询的帮助。

于 2013-04-10T02:18:44.220 回答
0

如果序列号对于名称和型号是唯一的,则应按对象将其包含在您的组中。

如果不是,那么您有一个按名称和型号列出的连续剧列表,并且选择 first 或 default 可能是完全错误的,也就是说,我想不出您想要这样的场景。

于 2013-04-17T15:15:16.467 回答