带有连接、组和求和的 EF Linq 查询
EF Linq query with join, group and sum
尝试构造一个执行简单内部联接的 LINQ 查询,对数据进行分组并对其中两列求和。从我看到的例子来看,它看起来相当简单,但我一定是错过了一些东西。
public class Employee
{
public int Id { get; set; }
public int Name { get; set; }
}
public class Inventory
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public decimal OffSite { get; set; }
public decimal OnSite { get; set; }
}
public class InventoryTotal
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public decimal EmployeeOffSite { get; set; }
public decimal EmployeeOnSite { get; set; }
}
我创建的查询如下所示
var result = from a in db.Inventory
join b in db.Employee on a.EmployeeId equals b.Id
group new { a, b } by a.EmployeeId into c
select new InventoryTotal
{
EmployeeId = c.Key,
EmployeeName = c.Name,
EmployeeOffSite = c.Sum(d => d.a.OffSite),
EmployeeOnSite = c.Sum(d => d.a.OnSite)
};
一个问题似乎与 Name 列有关,这是我想从与 Employee 的连接中获得的唯一值。我想了解如何正确访问该列并更好地了解如何构建整个查询。
EmployeeName = c.Name 无效,我尝试过的其他一些组合也无效。
您必须将 名称 添加到分组键:
var result = from a in db.Inventory
join b in db.Employee on a.EmployeeId equals b.Id
group a by new { a.EmployeeId, a.Name } into c
select new InventoryTotal
{
EmployeeId = c.Key.EmployeeId,
EmployeeName = c.Key.Name,
EmployeeOffSite = c.Sum(d => d.OffSite),
EmployeeOnSite = c.Sum(d => d.OnSite)
};
所以你有两个 table:Employees
和 Inventories
。这两者之间存在一对多关系:每个 Employee 都有零个或多个 Inventories;每个Inventory恰好是一个Employee的Inventory,即外键EmployeeId所指的Employee。
要求: 从每个员工那里获取他的 ID 和姓名,以及他所有的 OffSite 和 OnSite 库存总数。
由于您使用的是 entity framework,因此可以通过三种方法完成此操作。一种是自己做 (Group-)Join,另一种是让 entity framework 做 (Group-)Join,最后,最直观的部分是使用 virtual ICollection<Inventory
.
自己做 GroupJoin
每当您有一对多关系时,例如学校与他们的学生、客户与他们的订单或员工与他们的库存,并且您想从“一”端开始,请考虑使用其中之一Queryable.GroupJoin.
的重载
另一方面,如果你想从“多”这边开始,如果你想要Student和他就读的学校,Order和下单的Customer,考虑使用Queryable.Join
你想获取“员工及其库存的(一些信息),所以我们将使用 GroupJoin。我将使用 GroupJoin 的重载和参数结果Selector,这样我们就可以指定我们想要的结果。
var inventoryTotals = dbContext.Employees.GroupJoin(dbContext.Inventories,
employee => employee.Id, // from every Employee take the primary key
inventory => inventory.EmployeeId, // from every Inventory take the foreign key
// parameter resultSelector: from every Employee, and all Inventories that have a foreign
// key that refers to this Employee, make one new
(employee, inventoriesOfThisEmployee) => new InventoryTotal
{
EmployeeId = employee.Id,
EmployeeName = employee.Name,
EmployeeOffSite = inventoriesOfThisEmployee
.Select(inventory => inventory.OffSite).Sum(),
EmployeeOnSite = inventoriesOfThisEmployee
.Select(inventory => inventory.OnSite).Sum(),
});
让 Entity Framework 执行 GroupJoin
这个感觉更自然一些,我们根据要求为每位员工 Select 一个 InventoryTotal。
var inventoryTotals = dbContext.Employees.Select(employee => new InventoryTotal
{
// Select the Employee properties that you want.
EmployeeId = employee.Id,
EmployeeName = employee.Name,
// Get the inventories of this Employee:
EmployeeOffSite = dbContext.Inventories
.Where(inventory => inventory.EmployeeId == employee.Id)
.Select(inventory => inventory.OffSite).Sum(),
EmployeeOnSite = dbContext.Inventories
.Where(inventory => inventory.EmployeeId == employee.Id)
.Select(inventory => inventory.OnSite).Sum(),
});
使用虚拟 ICollections
这张感觉最自然。在没有真实数据库的情况下也很容易对您的使用情况进行单元测试。
如果您遵循了 entity framework conventions,您将 类 类似于:
public class Employee
{
public int Id { get; set; }
public int Name { get; set; }
... // other properties
// Every Employee has zero or more Inventories (one-to-many)
public ICollection<Inventory> Inventories {get; set;}
}
public class Inventory
{
public int Id { get; set; }
public decimal OffSite { get; set; }
public decimal OnSite { get; set; }
... // other properties
// Every Inventory is the Inventory of exactly one Employee, using foreign key
public int EmployeeId { get; set; }
public virtual Employee Employee {get; set;}
}
这足以让entity framework检测tables、tables的列以及与tables的关系(一对一许多,多对多,...)。仅当您想偏离约定时:tables 和列的不同标识符、非默认列类型等需要属性或流畅的 API。
In Entity framework the columns of the tables are represented by the non-virtual properties. The virtual properties represent the relations between the tables.
外键是table中的一列,因此是非虚拟的。 Inventory 没有 Employee 列,因此 属性 Employee 是虚拟的。
一旦定义了虚拟 ICollection,查询就很简单了:
要求: 从每个员工那里获取他的 ID 和姓名,以及他所有的 OffSite 和 OnSite 库存总数。
var inventoryTotals = dbContext.Employees.Select(employee => new InventoryTotal
{
// Select the Employee properties that you want.
EmployeeId = employee.Id,
EmployeeName = employee.Name,
EmployeeOffSite = employee.Inventories
.Select(inventory => inventory.OffSite).Sum(),
EmployeeOnSite = employee.Inventories
.Select(inventory => inventory.OnSite).Sum(),
});
简单的comme bonjour!
尝试构造一个执行简单内部联接的 LINQ 查询,对数据进行分组并对其中两列求和。从我看到的例子来看,它看起来相当简单,但我一定是错过了一些东西。
public class Employee
{
public int Id { get; set; }
public int Name { get; set; }
}
public class Inventory
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public decimal OffSite { get; set; }
public decimal OnSite { get; set; }
}
public class InventoryTotal
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public decimal EmployeeOffSite { get; set; }
public decimal EmployeeOnSite { get; set; }
}
我创建的查询如下所示
var result = from a in db.Inventory
join b in db.Employee on a.EmployeeId equals b.Id
group new { a, b } by a.EmployeeId into c
select new InventoryTotal
{
EmployeeId = c.Key,
EmployeeName = c.Name,
EmployeeOffSite = c.Sum(d => d.a.OffSite),
EmployeeOnSite = c.Sum(d => d.a.OnSite)
};
一个问题似乎与 Name 列有关,这是我想从与 Employee 的连接中获得的唯一值。我想了解如何正确访问该列并更好地了解如何构建整个查询。
EmployeeName = c.Name 无效,我尝试过的其他一些组合也无效。
您必须将 名称 添加到分组键:
var result = from a in db.Inventory
join b in db.Employee on a.EmployeeId equals b.Id
group a by new { a.EmployeeId, a.Name } into c
select new InventoryTotal
{
EmployeeId = c.Key.EmployeeId,
EmployeeName = c.Key.Name,
EmployeeOffSite = c.Sum(d => d.OffSite),
EmployeeOnSite = c.Sum(d => d.OnSite)
};
所以你有两个 table:Employees
和 Inventories
。这两者之间存在一对多关系:每个 Employee 都有零个或多个 Inventories;每个Inventory恰好是一个Employee的Inventory,即外键EmployeeId所指的Employee。
要求: 从每个员工那里获取他的 ID 和姓名,以及他所有的 OffSite 和 OnSite 库存总数。
由于您使用的是 entity framework,因此可以通过三种方法完成此操作。一种是自己做 (Group-)Join,另一种是让 entity framework 做 (Group-)Join,最后,最直观的部分是使用 virtual ICollection<Inventory
.
自己做 GroupJoin
每当您有一对多关系时,例如学校与他们的学生、客户与他们的订单或员工与他们的库存,并且您想从“一”端开始,请考虑使用其中之一Queryable.GroupJoin.
的重载另一方面,如果你想从“多”这边开始,如果你想要Student和他就读的学校,Order和下单的Customer,考虑使用Queryable.Join
你想获取“员工及其库存的(一些信息),所以我们将使用 GroupJoin。我将使用 GroupJoin 的重载和参数结果Selector,这样我们就可以指定我们想要的结果。
var inventoryTotals = dbContext.Employees.GroupJoin(dbContext.Inventories,
employee => employee.Id, // from every Employee take the primary key
inventory => inventory.EmployeeId, // from every Inventory take the foreign key
// parameter resultSelector: from every Employee, and all Inventories that have a foreign
// key that refers to this Employee, make one new
(employee, inventoriesOfThisEmployee) => new InventoryTotal
{
EmployeeId = employee.Id,
EmployeeName = employee.Name,
EmployeeOffSite = inventoriesOfThisEmployee
.Select(inventory => inventory.OffSite).Sum(),
EmployeeOnSite = inventoriesOfThisEmployee
.Select(inventory => inventory.OnSite).Sum(),
});
让 Entity Framework 执行 GroupJoin
这个感觉更自然一些,我们根据要求为每位员工 Select 一个 InventoryTotal。
var inventoryTotals = dbContext.Employees.Select(employee => new InventoryTotal
{
// Select the Employee properties that you want.
EmployeeId = employee.Id,
EmployeeName = employee.Name,
// Get the inventories of this Employee:
EmployeeOffSite = dbContext.Inventories
.Where(inventory => inventory.EmployeeId == employee.Id)
.Select(inventory => inventory.OffSite).Sum(),
EmployeeOnSite = dbContext.Inventories
.Where(inventory => inventory.EmployeeId == employee.Id)
.Select(inventory => inventory.OnSite).Sum(),
});
使用虚拟 ICollections
这张感觉最自然。在没有真实数据库的情况下也很容易对您的使用情况进行单元测试。
如果您遵循了 entity framework conventions,您将 类 类似于:
public class Employee
{
public int Id { get; set; }
public int Name { get; set; }
... // other properties
// Every Employee has zero or more Inventories (one-to-many)
public ICollection<Inventory> Inventories {get; set;}
}
public class Inventory
{
public int Id { get; set; }
public decimal OffSite { get; set; }
public decimal OnSite { get; set; }
... // other properties
// Every Inventory is the Inventory of exactly one Employee, using foreign key
public int EmployeeId { get; set; }
public virtual Employee Employee {get; set;}
}
这足以让entity framework检测tables、tables的列以及与tables的关系(一对一许多,多对多,...)。仅当您想偏离约定时:tables 和列的不同标识符、非默认列类型等需要属性或流畅的 API。
In Entity framework the columns of the tables are represented by the non-virtual properties. The virtual properties represent the relations between the tables.
外键是table中的一列,因此是非虚拟的。 Inventory 没有 Employee 列,因此 属性 Employee 是虚拟的。
一旦定义了虚拟 ICollection,查询就很简单了:
要求: 从每个员工那里获取他的 ID 和姓名,以及他所有的 OffSite 和 OnSite 库存总数。
var inventoryTotals = dbContext.Employees.Select(employee => new InventoryTotal
{
// Select the Employee properties that you want.
EmployeeId = employee.Id,
EmployeeName = employee.Name,
EmployeeOffSite = employee.Inventories
.Select(inventory => inventory.OffSite).Sum(),
EmployeeOnSite = employee.Inventories
.Select(inventory => inventory.OnSite).Sum(),
});
简单的comme bonjour!