我的查询会返回与特定排名匹配的人员列表。我希望它返回所有位置的列表,即使没有人匹配该位置。我加入别人的原因是因为我需要计算"已分配"这是一个与位置匹配的动态添加计数字段。但是,如果没有人匹配这个位置,我希望它仍然可以返回这个位置,但是想要" 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());
我面临的另一个问题是,在剃须刀页面上,公司正在重复。我需要公司前往每家公司只出现一次,但希望所有职位都列在其下方。
@model IEnumerable<dynamic>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>@ViewBag.Title</h2>
<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 (dynamic item in Model)
{
<thead>
<tr>
<th class="panel-bg" colspan="6">@item.Company</th>
</tr>
</thead>
<tbody>
<tr>
<td class="col-sm-1"></td>
<td class="col-sm-2">@item.Grade</td>
<td class="col-sm-2">@item.Series</td>
<td class="col-sm-2">@item.Payband</td>
<td class="col-sm-2">@item.Authorized</td>
<td class="col-sm-2">@item.Assigned</td>
</tr>
</tbody>
}
</table>
非常感谢任何帮助!
编辑(根据要求添加了Positions.cs类)
namespace CPR.Models
{
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class Positions
{
public Positions()
{
}
[Key]
public int Id { get; set; }
[Required]
public int CompanyId { get; set; }
[Required]
public int SeriesId { get; set; }
[Required]
public int GradeId { get; set; }
[Required]
public int PaybandId { get; set; }
[Required]
public int Authorized { get; set; }
public virtual Companies Companies { get; set; }
public virtual Series Series { get; set; }
public virtual Grades Grades { get; set; }
public virtual Paybands Paybands { get; set; }
}
}
答案 0 :(得分:2)
您需要稍微更改查询中的逻辑以便更早地计算,然后事情会变得更容易一些。请参阅以下代码段中的评论:
...
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
属性并呈现每行公司名称行下的项目。
此外,由于有多个thead
代码为not allowed,因此您生成的HTML不是100%有效。这是一个经过编辑的版本:
...
@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; }
}
然后根据上面的更新更新代码。
答案 1 :(得分:-1)
&#34;我希望它返回所有职位的清单,即使没有 匹配职位的人。&#34;
正如您所说,您应该只做下一步(编辑此部分):
之前:
from a in db.Positions
join b in db.People
之后:
from a in db.Positions
left join b in db.People
正如您所看到的,我应用了left join
,因为SQL LEFT JOIN
会返回左表中的所有行,即使右表中没有匹配项也是如此。这意味着如果ON子句匹配右表中的0(零)记录;连接仍会在结果中返回一行,但右表中的每列都有NULL。
这意味着左连接返回左表中的所有值,加上右表中的匹配值,如果没有匹配的连接谓词,则返回NULL。
我希望这对你有帮助, 干杯