简体   繁体   English

GroupBy实体框架核心中查找表的第一个结果

[英]GroupBy first result of lookup table in Entity Framework Core

I'm trying to get the total Man Days worked by volunteers per section between a date range. 我正在尝试获取一个日期范围内每个部分志愿者工作的总工时。 There is an attendance table which includes the day and the member id to map to the member table. 有一个考勤表,其中包括要映射到会员表的日期和会员ID。 There is also a section table to list all the sections and a membertosection table as a member can be in more than one section. 还有一个节表来列出所有节,并且一个membertosection表是一个成员可以在多个节中。

I want to group by the first section a member is in and then have a count of all the attendance days for that section. 我想按成员所在的第一部分分组,然后计算该部分的所有出勤天数。

The following works perfectly where I'm grouping by a 1 to many field (Category) on the members table but I can't work out how to change this to the first section (If the member has a section) 在将成员表上的1到多个字段(类别)分组的情况下,以下代码非常有效,但是我不知道如何将其更改为第一部分(如果成员具有部分)

var result = await _context.Attendance
                .Where(p => p.Day >= firstDayOfLastQuarter && p.Day <= lastDayOfLastQuarter)
                .GroupBy(p => p.Member.Category.Name)
                .Select(p => new { key = p.Key, count = p.Count() })
                .ToListAsync();

I'm looking for something like 我正在寻找类似的东西

var result = await _context.Attendance
                .Where(p => p.Day >= firstDayOfLastQuarter && p.Day <= lastDayOfLastQuarter && p.Member.MemberToSection.Any(s => s.MemberId == p.MemberId))
                .GroupBy(p => p.Member.MemberToSection.First().Section.Name)
                .Select(p => new { key = p.Key, count = p.Count() })
                .ToListAsync();

Update 更新资料

T-Sql code that produces the desired result is 产生预期结果的T-Sql代码是

SELECT Count(*) as Total, Section.Name
FROM Attendance
LEFT JOIN Member on Attendance.Member_Id = Member.Id
OUTER APPLY (
  SELECT TOP(1) sec.id, sec.Name
  FROM MemberToSection m2s
  LEFT JOIN Section sec ON m2s.Section_Id = sec.Id
  WHERE m2s.Member_Id = Member.Id 
) as Section
WHERE Attendance.Day >= '2016-10-01' AND Attendance.Day <= '2016-12-31'
GROUP BY Section.Name

The "something like" code returns the error “类似”代码返回错误

An unhandled exception occurred while processing the request.

ArgumentException: Property 'System.String Name' is not defined for type 'Microsoft.EntityFrameworkCore.Storage.ValueBuffer'

Classes 班级

As requested here are the relevant classes 根据要求,这里是相关的类

Attendance.cs 出勤率

public partial class Attendance
{
    public long Pk { get; set; }
    public int MemberId { get; set; }
    public DateTime Day { get; set; }

    public virtual Member Member { get; set; }
}

Member.cs Member.cs

public partial class Member
{
    public Member()
    {
        MemberToSection = new HashSet<MemberToSection>();
    }

    public int Id { get; set; }
    public int? CategoryId { get; set; }

    public virtual ICollection<MemberToSection> MemberToSection { get; set; }
}

MemberToSection.cs MemberToSection.cs

public partial class MemberToSection
{
    public int SectionId { get; set; }
    public int MemberId { get; set; }

    public virtual Member Member { get; set; }
    public virtual Section Section { get; set; }
}

Section.cs Section.cs

public partial class Section
{
    public Section()
    {
        MemberToSection = new HashSet<MemberToSection>();
    }

    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<MemberToSection> MemberToSection { get; set; }
}

The (currently combined) EF documentation starts with Compare EF Core & EF6.x section which contains the very "useful" topic Which One Is Right for You . (当前合并的)EF 文档从“ 比较EF核心和EF6.x”部分开始,其中包含非常“有用的”主题“ 一个适合您” Well, looks like EF Core is not for you (yet). 好吧,看起来EF Core还不适合您。 The following applies to latest at this time EF Core v1.1.0. 以下内容适用于当前最新的EF Core v1.1.0。

First, GroupBy (even by simple primitive property) is always processed in memory. 首先, GroupBy (甚至通过简单的原始属性)始终在内存中处理。

Second, there are a lot of internal bugs causing exceptions when processing pretty valid LINQ queries like yours. 其次,在处理像您这样的非常有效的LINQ查询时,有很多内部错误会导致异常。

Third, after some trial and error, the following equivalent construct works for your case (at least does not generate exceptions): 第三,经过反复试验,以下等效构造适用于您的情况(至少不会生成异常):

.GroupBy(p => p.Member.MemberToSection.Select(m => m.Section.Name).FirstOrDefault())

(btw, irrelevant to the issue, the s => s.MemberId == p.MemberId condition inside the p.Member.MemberToSection.Any call is redundant because it is enforced by the relationship, so simple Any() would do the same.) (顺便说一句,与这一问题无关,则s => s.MemberId == p.MemberId内部条件p.Member.MemberToSection.Any ,因为它是由关系执行呼叫是冗余的,因此简单Any()会做同样的)

But now not only the GroupBy is performed in memory, but also the query is causing N + 1 SQL queries similar to EF Core nested Linq select results in N + 1 SQL queries . 但是现在,不仅GroupBy在内存中执行,而且查询导致N + 1个SQL查询,类似于EF Core嵌套的Linq select结果在N + 1个SQL查询中 Congratulations :( 恭喜您:(

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

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