简体   繁体   中英

Using LINQ SelectMany() to join multiple child tables without a navigation property

I kind of got confused on how to achieve what I want, and after searching in the internet, I think SelectMany() is the way to go, but I am getting lost on how to make this work ( I have very weak understanding of how lambda expressions work I think )..

My goal is to be able to use LINQ to populate this class:

public class AttendanceList
{
    public int AttendancePeriodId { get; set; }     // from AttendancePeriod class
    public int Activity { get; set; }               // from DailyAttendance class
    public string Name { get; set; }                // from Employee class
    public string Position { get; set; }            // from Employee class
    public string Department { get; set; }          // from Employee class
}

I have a totally wrong and non-working code, but to illustrate, I wanna use something like:

var query = context.AttendancePeriod
    .Include(i => i.DailyAttendance)
    .Include(i => i.DailyAttendance).ThenInclude(ii => ii.Employee)
    .Select(s => new AttendanceList
    {
        AttendancePeriodId = s.Id,
        Activity = ...,
        Name = ...,
        Position = ...,
        Department = ...
    });

How do I use SelectMany() to achieve the above?

For reference, these are my classes:

public class AttendancePeriod
{
    public int Id { get; set; }
    public DateTime From { get; set; }
    public DateTime To { get; set; }
    public ICollection<DailyAttendance> DailyAttendances { get; set; }
}

public class DailyAttendance
{
    public int Id { get; set; }
    public Employee Employee { get; set; }
    public TimeSpan TimeIn { get; set; }
    public TimeSpan TimeOut { get; set; }
    public string Activity { get; set;}
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Position { get; set; }
    public string Department { get; set; }
}

Untested and without any null checking:

var query = context.AttendancePeriod
  // .Include(i => i.DailyAttendance)  
  // .Include(i => i.DailyAttendance).ThenInclude(ii => ii.Employee)
   .SelectMany(s => s.DailyAttendances.Select(a => 
      new AttendanceList
      {
          AttendancePeriodId = s.Id,
          Activity = a.Activity ,
          Name = a.Employee.Name,
          Position = a.Employee.Position,
          Department = a.Employee.Department,
      }));

Maybe you are looking for this

First step get a flat list of all DailyAttendances

.SelectMany(x => x.DailyAttendances)

Now transform those into AttendanceList

.Select(x => new AttendanceList
{
    //x is of type `DailyAttendance`

    AttendancePeriodId = x.AttendancePeriod.Id,
    Activity = x.Activity,
    Name = x.Employee.Name,
    Position = x.Employee.Position,
    Department = x.Employee.Department,
}

If DailyAttendance doesn't have a member for AttendancePeriod you could do the following, instead of

.SelectMany(x => x.DailyAttendances)

use this, this will create a tuple contains x = AttendancePeriod and y = DailyAttendance

.SelectMany(x => x.DailyAttendances.Select(y => (x, y))

and now transform it to this

.Select(x => new AttendanceList
{
    //x is of type `ValueTuple<AttendancePeriod, DailyAttendance>`
    //x.Item1 is of type AttendancePeriod
    //x.Item2 is of type DailyAttendance

    AttendancePeriodId = x.Item1.Id,
    Activity = x.Item2.Activity,
    Name = x.Item2.Employee.Name,
    Position = x.Item2.Employee.Position,
    Department = x.Item2.Employee.Department,
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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