如何使用 LINQ group by 子句返回唯一的员工行?
Posted
技术标签:
【中文标题】如何使用 LINQ group by 子句返回唯一的员工行?【英文标题】:How do I use LINQ group by clause to return unique employee rows? 【发布时间】:2021-04-28 01:59:54 【问题描述】:我对 LINQ 还很陌生,我一辈子都搞不明白。我看过很多关于如何在 LINQ 中使用 group by 的帖子,但由于某种原因,我无法让它工作。这在 ADO.NET 中非常简单,但我正在尝试使用 LINQ。这是我所拥有的与问题相关的内容。我已经标记了不起作用的部分。
public class JoinResult
public int LocationID;
public int EmployeeID;
public string LastName;
public string FirstName;
public string Position;
public bool Active;
private IQueryable<JoinResult> JoinResultIQueryable;
public IList<JoinResult> JoinResultIList;
JoinResultIQueryable = (
from e in IDDSContext.Employee
join p in IDDSContext.Position on e.PositionID equals p.PositionID
join el in IDDSContext.EmployeeLocation on e.EmployeeID equals el.EmployeeID
where e.PositionID != 1 // Do not display the super administrator's data.
orderby e.LastName, e.FirstName
// ***** Edit: I forgot to add this line of code, which applies a filter
// ***** to the IQueryable. It is this filter (or others like it that I
// ***** have omitted) that causes the query to return multiple rows.
// ***** The EmployeeLocationsList contains multiple LocationIDs, hence
// ***** the duplicates employees that I need to get rid of.
JoinResultIQueryable = JoinResultIQueryable
.Where(e => EmployeeLocationsList.Contains(e.LocationID);
// *****
// ***** The following line of code is what I want to do, but it doesn't work.
// ***** I just want the above join to bring back unique employees with all the data.
// ***** Select Distinct is way too cumbersome, so I'm using group by.
group el by e.EmployeeID
select new JoinResult
LocationID = el.LocationID,
EmployeeID = e.EmployeeID,
LastName = e.LastName,
FirstName = e.FirstName,
Position = p.Position1,
Active = e.Active
)
.AsNoTracking();
JoinResultIList = await JoinResultIQueryable
.ToListAsync();
如何从 IQueryable 到 IList 只返回唯一的员工行?
***** 编辑: 这是我当前的输出:
[4][4][Anderson (OH)][Amanda][Dentist][True]
[5][4][Anderson (OH)][Amanda][Dentist][True]
[4][25][Stevens (OH)][Sally][Dental Assistant][True]
[4][30][Becon (OH)][Brenda][Administrative Assistant][False]
[5][30][Becon (OH)][Brenda][Administrative Assistant][False]
【问题讨论】:
在使用 linq 进行分组时,您应该使用 into 运算符,例如,将 e.EmployeeID 分组为 g,然后使用 g 是 select e.x ***.com/questions/7325278/group-by-in-linq 谢谢。我试了一下,但它对我不起作用。 :) 根据您的数据,您的位置和员工之间似乎存在一对多关系正确吗? 请看我下面的回答 是的。 Employee 和 EmployeeLocation 之间存在一对多的关系。 【参考方案1】:其实这里不需要分组,而是Distinct
。在Distinct
或分组之前订购是没有用的。也不需要带有自定义投影的AsNoTracking
。
var query =
from e in IDDSContext.Employee
join p in IDDSContext.Position on e.PositionID equals p.PositionID
join el in IDDSContext.EmployeeLocation on e.EmployeeID equals el.EmployeeID
where e.PositionID != 1 // Do not display the super administrator's data.
select new JoinResult
LocationID = el.LocationID,
EmployeeID = e.EmployeeID,
LastName = e.LastName,
FirstName = e.FirstName,
Position = p.Position1,
Active = e.Active
;
query = query.Distinct().OrderBy(e => e.LastName).ThenBy(e => e.FirstName);
JoinResultIList = await query.ToListAsync();
【讨论】:
我希望这会奏效,但它没有。我意识到 Distinct 是我在 SQL 中想要的。感谢您对 AsNoTracking() 的提醒。 这对我不起作用:query = query.Distinct().OrderBy(e => e.LastName).ThenBy(e => e.FirstName);它没有改变任何东西。我也为你添加了输出,所以你可以看到。【参考方案2】:问题是很少有员工拥有多个地点导致结果重复。您可以通过多种方式处理它。我使用Let 子句来解决以下示例中的问题
public class Employee
public string FirstName get; set;
public string LastName get; set;
public int EmployeeID get; set;
public int PositionID get; set;
public class EmployeeLocation
public int EmployeeID get; set;
public int LocationID get; set;
public class Position
public int PositionID get; set;
public string Position1 get; set;
public class Location
public int LocationID get; set;
public class JoinResult
//Suggestion : Insetad of LocationID there should be a varibale that has all the locations of an employee
public IEnumerable<int> LocationIDs;
public int LocationID;
public int EmployeeID;
public string LastName;
public string FirstName;
public string Position;
public bool Active;
//Setting up mock data
List<Position> positions = new List<Position>();
positions.Add(new Position() Position1 = "Dentist", PositionID = 2 );
positions.Add(new Position() Position1 = "Dental Assistant", PositionID = 3 );
positions.Add(new Position() Position1 = "Administrative Assistant", PositionID = 4 );
List<Employee> employees = new List<Employee>();
employees.Add(new Employee() EmployeeID = 4, FirstName = "Amanda", LastName = "Anderson (OH)", PositionID = 2 );
employees.Add(new Employee() EmployeeID = 25, FirstName = "Sally", LastName = "Stevens (OH)", PositionID = 3 );
employees.Add(new Employee() EmployeeID = 30, FirstName = "Brenda", LastName = "Becon (OH)", PositionID = 4 );
List<Location> locations = new List<Location>();
locations.Add(new Location() LocationID = 4 );
locations.Add(new Location() LocationID = 5 );
List<EmployeeLocation> employeeLocation = new List<EmployeeLocation>();
employeeLocation.Add(new EmployeeLocation() LocationID = 4, EmployeeID = 4 );
employeeLocation.Add(new EmployeeLocation() LocationID = 5, EmployeeID = 4 );
employeeLocation.Add(new EmployeeLocation() LocationID = 4, EmployeeID = 25 );
employeeLocation.Add(new EmployeeLocation() LocationID = 4, EmployeeID = 30 );
employeeLocation.Add(new EmployeeLocation() LocationID = 5, EmployeeID = 30 );
var result = (from e in employees
join p in positions on e.PositionID equals p.PositionID
let employeeLocations = (from el in employeeLocation where el.EmployeeID == e.EmployeeID select new LocationID = el.LocationID )
where e.PositionID != 1 // Do not display the super administrator's data.
orderby e.LastName, e.FirstName
select new JoinResult
LocationID = employeeLocations.Select(p=>p.LocationID).First()//Here its just selecting the first location,
LocationIDs = employeeLocations.Select(p=> p.LocationID),//This is my suggestion
EmployeeID = e.EmployeeID,
LastName = e.LastName,
FirstName = e.FirstName,
Position = p.Position1,
).ToList();
【讨论】:
【参考方案3】:好的。所以这是我想出的解决方案。我安装了 morelinq NuGet 包,其中包含 DistinctBy() 方法。然后我将该方法添加到问题中显示的代码的最后一行。
JoinResultIList = JoinResultIQueryable
.DistinctBy(jr => jr.EmployeeID)
.ToList();
【讨论】:
以上是关于如何使用 LINQ group by 子句返回唯一的员工行?的主要内容,如果未能解决你的问题,请参考以下文章
LINQ to Sql 左外连接与 Group By 和 Have 子句
Postgresql“列必须出现在 GROUP BY 子句中或在聚合函数中使用”和唯一字段
LINQ Group By并将Group的子列表合并回唯一列表