简体   繁体   English

LINQ GroupBy子集合属性

[英]LINQ GroupBy child collection properties

I'm trying to find a way to group a list using LINQ not only by properties of the Foo object (EmployeeId, CompanyId and GroupId) but ONLY group them if the StartDate and EndDate properties of the Baz objects are exactly the same. 我试图找到一种方法,不仅使用Foo对象的属性(EmployeeId,CompanyId和GroupId)使用LINQ来对列表进行分组,而且仅当Baz对象的StartDate和EndDate属性完全相同时才对它们进行分组。 The goal is to group by EmployeeId, CompanyId and GroupId and combine the Bars collections to be an aggregate of all of the grouped records. 目标是按EmployeeId,CompanyId和GroupId分组,并将Bars集合合并为所有分组记录的集合。

So if List has three objects, and the Bars collection on the first object are all BazId=1, the second BazId=2 and the third BazId=3, I would expect a result where List contains TWO objects one with a Bars collection that has BazIds of 1 and 3 and another that has a Bars collection with BazIds of 2 (since 1 and 3 share the same start/end dates, as outlined below). 因此,如果List具有三个对象,并且第一个对象上的Bars集合都是BazId = 1,第二个BazId = 2,第三个BazId = 3,则我希望得到这样一个结果,其中List包含两个对象,其中两个对象的Bars集合具有BazIds为1和3,另一个具有Bars集合的BazIds为2(因为1和3共享相同的开始/结束日期,如下所述)。

I hope this makes sense. 我希望这是有道理的。 I've been awake for far too long so if this is unclear, let me know and I'll do my best to clarify. 我已经醒了很久,所以如果不清楚,请告诉我,我会尽力澄清。

What I have so far is: 到目前为止,我有:

var result = foos.GroupBy(g => new { g.CompanyId, g.EmployeeId, g.GroupId })
        .Select(g => new Foo(g.Key.CompanyId, g.Key.EmployeeId, g.Key.GroupId)
        {
          Bars = g.SelectMany(x => x.Bars)}
).ToList();

However, this ignores the StartDate/EndDate properties of the corresponding Baz objects. 但是,这将忽略相应Baz对象的StartDate / EndDate属性。 I ONLY want to group the records for Foo objects whose Bars collection has BazIds that share the same start/end dates. 我只想对Foo对象的记录进行分组,这些对象的Bars集合具有共享相同开始/结束日期的BazId。

EDIT: It is a business rule that all Bar objects within a given Bars collection will have the same BazId 编辑:这是一条业务规则,即给定Bars集合内的所有Bar对象将具有相同的BazId

public class Foo {
  public int EmployeeId { get; set; }
  public int CompanyId { get; set;
  public int GroupId { get; set; }

  public List<Bar> Bars { get; set; }
}


public class Bar {
  public BazId { get; set; }
  public string Name { get; set; }
}

public class Baz {
  public int Id { get; set; }
  public DateTime StartDate { get; set; }
  public DateTime EndDate { get; set; }
}

var baz = new List<Baz> {
  new Baz {
    Id = 1,
    StartDate = DateTime.Now,
    EndDate = DateTime.Now.AddMonths(1)
  },
  new Baz {
    Id = 2,
    StartDate = DateTime.Now.AddMonths(-1),
    EndDate = DateTime.Now.AddMonths(1)
  },
  new Baz {
    Id = 3,
    StartDate = DateTime.Now,
    EndDate = DateTime.Now.AddMonths(1)
  },
}

SOLUTION What I ended up with is this, based on the comment from @jdweng: 解决方案基于@jdweng的评论,我最终得出的结论是:

var result = foos.GroupBy(g => g, new FooComparer())
            .Select(g => new Foo(g.Key.CompanyId, g.Key.EmployeeId, g.Key.GroupId)
            {
              Bars = g.SelectMany(x => x.Bars)}
    ).ToList();

Within FooComparer , I implemented IEqualityComparer<Foo> and created Equals and GetHashCode methods that determined whether or not the two were equal by examining the Baz collections of each. FooComparer ,我实现了IEqualityComparer<Foo>并创建了EqualsGetHashCode方法,这些方法通过检查每个Baz集合来确定两者是否相等。

It seems that you have to include in grouping Start and End dates. 似乎您必须将开始和结束日期分组。 For that you have to join with Baz. 为此,您必须加入Baz。

var bazs = new List<Baz> {
    new Baz {
        Id = 1,
        StartDate = DateTime.Today,
        EndDate = DateTime.Today.AddMonths(1)
    },
    new Baz {
        Id = 2,
        StartDate = DateTime.Today.AddMonths(-1),
        EndDate = DateTime.Today.AddMonths(1)
    },
    new Baz {
        Id = 3,
        StartDate = DateTime.Today,
        EndDate = DateTime.Today.AddMonths(1)
    }
};

List<Foo> foos = new List<Foo>{
    new Foo
    {
        EmployeeId = 1,
        CompanyId = 2,
        GroupId = 3,
        Bars = new List<Bar> {
            new Bar { BazId = 1 },
            new Bar { BazId = 2 },
            new Bar { BazId = 3 }
        }
    }
};

var result = (from extendedBar in foos.SelectMany(f => f.Bars.Select(b => new { Bar = b, f.EmployeeId, f.CompanyId, f.GroupId }))
              join baz in bazs
              on extendedBar.Bar.BazId equals baz.Id
              select new { extendedBar.Bar, extendedBar.EmployeeId, extendedBar.CompanyId, extendedBar.GroupId, baz.StartDate, baz.EndDate })
                .GroupBy(o => new { o.EmployeeId, o.CompanyId, o.GroupId, o.StartDate, o.EndDate })
                .Select(g => new Foo { EmployeeId = g.Key.EmployeeId, CompanyId = g.Key.CompanyId, GroupId = g.Key.GroupId, Bars = g.Select(o => o.Bar).ToList() })
             .ToList();

Try adding an inheritance to the class IComparable with the method CompareTo(). 尝试使用CompareTo()方法向类IComparable添加继承。 The Linq Groupby will use the CompareTo method for the groupings Linq Groupby将使用CompareTo方法进行分组

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM