C# LINQ返回MVC5 Razor视图上的所有记录和groupby

C# LINQ返回MVC5 Razor视图上的所有记录和groupby,c#,asp.net-mvc,linq,razor,C#,Asp.net Mvc,Linq,Razor,我的查询返回与特定职位匹配的人员列表。我希望它返回所有职位的列表,即使没有匹配该职位的人。我加入people的原因是因为我需要“Assigned”的计数,这是一个动态添加的计数字段,与职位匹配。但是,如果没有与该职位匹配的人员,我希望它仍然返回计费的职位,但希望“Assigned”设置为0 dynamic query = (from a in db.Positions join b in db.People

我的查询返回与特定职位匹配的人员列表。我希望它返回所有职位的列表,即使没有匹配该职位的人。我加入people的原因是因为我需要“Assigned”的计数,这是一个动态添加的计数字段,与职位匹配。但是,如果没有与该职位匹配的人员,我希望它仍然返回计费的职位,但希望“Assigned”设置为0

    dynamic query = (from a in db.Positions
                     join b in db.People 
                     on new { 
                         a.GradeId, 
                         a.SeriesId, 
                         a.CompanyId, 
                         a.PaybandId }
                     equals new { 
                         b.GradeId, 
                         b.SeriesId, 
                         b.CompanyId, 
                         b.PaybandId } into ab
                     from k in ab.DefaultIfEmpty()
                     join c in db.Grades on k.GradeId equals c.Id
                     join d in db.Series on k.SeriesId equals d.Id
                     join e in db.Companies on k.CompanyId equals e.Id
                     join p in db.Paybands on k.PaybandId equals p.Id
                     group a by new { CompanyName = e.Name, 
                         GradeName = c.Name, 
                         SeriesName = d.Name, 
                         PaybandName = p.Name, 
                         a.Authorized } into f
                     select new { Company = f.Key.CompanyName, 
                         Grade = f.Key.GradeName, 
                         Series = f.Key.SeriesName, 
                         Payband = f.Key.PaybandName, 
                         Authorized = f.Key.Authorized, 
                         Assigned = f.Count() }).AsEnumerable().Select(r => r.ToExpando());
我面临的另一个问题是,在razor页面上,该公司正在重复。我需要的公司标题,以显示每个公司只有一次,但希望所有职位都列在下面

以下是视图屏幕截图和razor脚本:

“我希望它能返回所有职位的列表,即使没有 与职位匹配的人。”

正如您所说,您只需执行下一步(编辑此部分):

之前:

from a in db.Positions
join b in db.People 
之后:

from a in db.Positions
left join b in db.People 
正如您所看到的,我应用了
左联接
,因为SQL
左联接
返回左表中的所有行,即使右表中没有匹配项。这意味着,如果ON子句与右表中的0(零)条记录匹配;联接仍将在结果中返回一行,但右表中的每一列都返回NULL

这意味着左连接返回左表中的所有值,加上右表中的匹配值,如果没有匹配的连接谓词,则返回NULL

我希望这对你有帮助,
干杯

您需要稍微更改查询中的逻辑,以便更早地计数,然后事情就会变得简单一些。请参见下面代码段中的注释:

            ...

            from a in db.Positions
                 join b in db.People 
                 on new { 
                     a.GradeId, 
                     a.SeriesId, 
                     a.CompanyId, 
                     a.PaybandId }
                 equals new { 
                     b.GradeId, 
                     b.SeriesId, 
                     b.CompanyId, 
                     b.PaybandId } into ab
                 from k in ab.DefaultIfEmpty()

                 // you want to count the number of people per position here

                 group k by new { a.GradeId, a.SeriesId, a.CompanyId, a.PaybandId, a.Authorized } into g
                 select new { g.Key.GradeId, g.Key.SeriesId, g.Key.CompanyId, g.Key.PaybandId, g.Authorized, Count = g.Count(p => p != null) } into counts

                 // at this point you have position info AND people count per position
                 // next, you can do the remaining joins...

                 join c in db.Grades on counts.GradeId equals c.Id
                 join d in db.Series on counts.SeriesId equals d.Id
                 join e in db.Companies on counts.CompanyId equals e.Id
                 join p in db.Paybands on counts.PaybandId equals p.Id

                 // ... and select full data set, including person count, required for the view

                 select new { 
                    CompanyName = e.Name,
                    GradeName = c.Name,
                    SeriesName = d.Name, 
                    PaybandName = p.Name,
                    counts.Authorized,
                    Assigned = counts.Count
                 } into full

                 // one more step here that will help to tackle your second problem (grouping by company name in the view)
                 // you want your data coming into the view be grouped by company name 

                 group full by full.CompanyName into groupByCompany

                 select new CompanyInfo { CompanyName = groupByCompany.Key, CompanyItems = groupByCompany.Select(i => new CompanyItem { GradeName = i.GradeName, SeriesName = i.SeriesName, PaybandName = i.PaybandName, Authorized = i.Authorized, Assigned = i.Assigned }).ToList() }

                ...
然后在视图中,您需要创建2个
@foreach
循环,而不是一个。第一个(外部)将在上面的集合上循环并呈现一次带有公司名称的行,而另一个(内部)将在集合中每个项目的
CompanyItems
属性上循环,并在公司名称行下呈现每个项目的行

此外,生成的HTML不是100%有效,因为存在多个
thead
标记。以下是经过编辑的版本:

...
@model IEnumerable<CompanyInfo>

<table class="table table-responsive table-hover">
    <thead>
        <tr>
            <th class="col-sm-1"></th>
            <th class="col-sm-2">Grade</th>
            <th class="col-sm-2">Series</th>
            <th class="col-sm-2">Payband</th>
            <th class="col-sm-2">Authorized</th>
            <th class="col-sm-2">Assigned</th>
        </tr>
    </thead>
    @foreach (CompanyInfo item in Model)
    {
        <tbody>
            <tr class="company-name">
                <th class="panel-bg" colspan="6">@item.CompanyName</th>
            </tr>
            @foreach (CompanyItem companyItem in item.CompanyItems)
            {
                <tr>
                    <td class="col-sm-1"></td>
                    <td class="col-sm-2">@companyItem.Grade</td>
                    <td class="col-sm-2">@companyItem.Series</td>
                    <td class="col-sm-2">@companyItem.Payband</td>
                    <td class="col-sm-2">@companyItem.Authorized</td>
                    <td class="col-sm-2">@companyItem.Assigned</td>
                </tr>
            }
        </tbody>
    }
</table>

...
。。。
@模型IEnumerable
等级
系列
工资带
经授权的
分配
@foreach(模型中的公司信息项)
{
@item.CompanyName
@foreach(项目中的CompanyItem CompanyItem.CompanyItems)
{
@公司项目等级
@公司项目系列
@公司项目工资带
@授权公司项目
@分配的公司项目
}
}
...
要使用强类型视图模型,请添加以下两个类:

class CompanyInfo
{
    public string CompanyName { get; set; }
    public List<CompanyItem> CompanyItems { get; set; }
}

class CompanyItem
{
    public string GradeName { get; set; }
    public string SeriesName { get; set; }
    public string PaybandName { get; set; }
    public bool Authorized { get; set; }
    public int Assigned { get; set; }
}
class公司信息
{
公共字符串CompanyName{get;set;}
公共列表公司项目{get;set;}
}
类公司项目
{
公共字符串GradeName{get;set;}
公共字符串序列名{get;set;}
公共字符串PaybandName{get;set;}
公共bool授权{get;set;}
公共int赋值{get;set;}
}

然后根据上面的更新更新代码。

你能添加你的职位类吗?@MichaelBurns-根据你的请求添加的“left join”不是有效的LINQ语法,不幸的是,否则这会简单得多:)惊人、彻底的答案。在您的实现中,我遇到了一些错误。1.名称“a”在当前上下文中不存在,而名称“2”匿名类型#1'不包含“计数”的定义。选择新建{CompanyName=e.Name,GradeName=c.Name,SeriesName=d.Name,PaybandName=p.Name,a.Authorized,//对不起,你是对的。修复了它们,请查看更新的代码。基本上,
Assigned=counts.Count()
应该被
分配=计数。计数
;至于
a.Authorized
,它应该被包括在第一组中,并从那里重新使用。另外,请注意
class=“company name”的用法
attr在视图中。由于我们去掉了多个
thead
s,因此需要使用CSS设置公司名称行的样式。这是由于动态模型和匿名类型的组合被用作模型。在运行时,匿名模型被视为一个对象,而对象没有我们试图访问的属性。因此,这里是best使用强类型视图模型。我现在将更新代码。不客气!请参阅更新的代码。您需要添加两个类,更新查询中的最终
select
,并更新视图。请告诉我是否还有其他ERORR。我必须在此处和此处进行一些小更改,并且缺少一个.Key。但是,sol这是坚如磐石,我感谢你一直以来对我的帮助和帮助。我对你的做法更加理解,从长远来看,这将帮助我。再次感谢你,兄弟!这是应得的赏金!(但要到17小时后才能颁发)
...
@model IEnumerable<CompanyInfo>

<table class="table table-responsive table-hover">
    <thead>
        <tr>
            <th class="col-sm-1"></th>
            <th class="col-sm-2">Grade</th>
            <th class="col-sm-2">Series</th>
            <th class="col-sm-2">Payband</th>
            <th class="col-sm-2">Authorized</th>
            <th class="col-sm-2">Assigned</th>
        </tr>
    </thead>
    @foreach (CompanyInfo item in Model)
    {
        <tbody>
            <tr class="company-name">
                <th class="panel-bg" colspan="6">@item.CompanyName</th>
            </tr>
            @foreach (CompanyItem companyItem in item.CompanyItems)
            {
                <tr>
                    <td class="col-sm-1"></td>
                    <td class="col-sm-2">@companyItem.Grade</td>
                    <td class="col-sm-2">@companyItem.Series</td>
                    <td class="col-sm-2">@companyItem.Payband</td>
                    <td class="col-sm-2">@companyItem.Authorized</td>
                    <td class="col-sm-2">@companyItem.Assigned</td>
                </tr>
            }
        </tbody>
    }
</table>

...
class CompanyInfo
{
    public string CompanyName { get; set; }
    public List<CompanyItem> CompanyItems { get; set; }
}

class CompanyItem
{
    public string GradeName { get; set; }
    public string SeriesName { get; set; }
    public string PaybandName { get; set; }
    public bool Authorized { get; set; }
    public int Assigned { get; set; }
}