EF6 中的内部连接查询
Inner join query in EF6
我需要一些帮助来查询我的 MVC 应用程序。
我在 SQL 中创建了这个查询:
SELECT Projects.ID, Projects.ProjectName, Employees.ID
FROM Projects INNER JOIN (Employees INNER JOIN ProjectEmployees ON Employees.ID = ProjectEmployees.EmployeeId) ON Projects.ID = ProjectEmployees.ProjectId
WHERE (((Employees.ID)=2));
它应该是这样的:
我如何使用 perahps LinQ 或其他适合我的 MVC 应用程序的格式重建它。
谢谢,卡斯滕
使用 LINQ 看起来像这样
from p in Projects
join pe in ProjectEmployees on p.ID equals pe.ProjectId
join e in Employees on pe.EmployeeID equals e.ID
where e.ID = 2
select new {
ProjectId = p.ID,
ProjectName = p.ProjectName,
EmployeeId = e.ID
}
评论后最后添加
您似乎在员工和项目之间设计了一个简单的多对多关系:每个员工在零个或多个项目上工作,每个项目都由零个或多个员工完成。
如果您遵循了 entity framework coding conventions,您将得到类似于:
class Employee
{
public int Id {get; set;}
public string Name {get; set;}
... // other Employee properties
// every Employee works on zero or more Projects, many-to-many
public virtual ICollection<Project> Projects {get; set;}
}
class Project
{
public int Id {get; set;}
public string Name {get; set;}
... // other Project properties
// every Project is done by zero or more Employees, many-to-many
public virtual ICollection<Employee> Employees {get; set;}
}
为了完整起见,DbContext:
class DbContext
{
public DbSet<Employee> Employees {get; set;}
public DbSet<Project> Projects {get; set;}
}
这就是 entity framework 检测多对多关系所需知道的全部内容。尽管未提及结点 table,但 entity framework 足够聪明,知道这种关系需要结点 table 并会为您创建它。
但是,如果我无法访问连接点 table,我该如何进行(组)加入?
答案:不要自己加入(组),使用虚拟 ICollection。
要求:给我Id为[2]的员工工作的项目(的一些属性)。
const int employeeId = 2;
var employeeWithHisProjects = dbContext.Employees
.Where(employee => employee.Id == 2)
.Select(employee => new
{
// For efficiency, select only the Employee properties that you plan to use:
Id = employee.Id,
Name = employee.Name,
...
Projects = employees.Projects
// Only if you don't want all Projects of Employee[2]:
// for example: Projects with DueDate before today:
.Where(project => project.DueDate <= today)
.Select(project => new
{
// again: only the project properties that you plan to use.
Id = project.Id,
Name = project.Name
...
})
.ToList(),
});
换句话说:从table个Employees中,只保留Id等于2的Employees。从剩下的Employees中,取Id,name和...;从他的项目中,只保留截止日期在今天或之前的那些项目。从剩余的项目中获取 Id、名称和...
Entity framework 知道你的多对多关系,并且足够聪明,可以为你做正确的(组)加入。
看看这感觉有多自然,尤其是如果您将其与您建议的内部联接进行比较?
Inner Join 和 GroupJoin 之间的小区别
请注意,两者之间存在细微差别。如果省略 Where Employee.Id == 2
,内部联接的结果将是:
Employee Project
2 A
2 B
3 A
4 C
3 C
2 C
4 B
使用 ICollection 或进行 GroupJoin 你会得到类似
的东西
- 员工[2] 及其项目 A、B、C
- 员工[3] 及其项目 A、C
- 员工[4] 和他的项目 B、C
- 没有任何项目的员工[5]
GroupJoin 给出了更自然的结果。 Employee [2] 的所选属性仅传输一次,即使他有 3 个项目。
更重要的是:您还会看到 Employee[5],即使他没有任何项目!
如何添加员工和项目
您可以在没有任何员工参与的情况下添加项目。您可以添加尚未从事任何项目的员工。
var addedProject = dbContext.Projects.Add(new Project()
{
// Id is filled when you SaveChanges
Name = "Improve Entity FrameWork",
...
// no one is working on this project yet, therefore no need to mention Employees
// or if you want, assign null, or empty collection
Employees = new Employee[],
});
var addedEmployee = dbContext.Employees.Add(new Employee()
{
// Id is filled when you SaveChanges
Name = "John Doe",
...
// John is not working on any Project yet
});
如果您想添加已经在多个项目中工作的员工:
// Select 3 projects suitable for new employees:
var projectsForNewEmployee = dbContext.Projects
.Where(project => project.Difficulty == Difficulty.LearningStage)
.OrderBy(project => project.Priority)
.Take(3);
var employeeWithSomeProjects = dbContext.Employees.Add(new Employee()
{
Name = "Max Rabe",
...
Projects = projectsForNewEmployee.ToList(),
});
假设我们要将员工 "Mary" 添加到项目 "Project X":
var projectX = dbContext.Projects
.Where(project => project.Name == "Project X")
.FirstOrDefault();
var mary = dbContext.Employees
.Where(employee => employee.Name == "Mary")
.FirstOrDefault(),
// Mary gets a new Project:
mary.Projects.Add(projectX);
dbContext.SaveChanges();
您也可以将 Mary 添加到 projectX:
projectX.Employees.Add(mary);
dbContext.SaveChanges();
这似乎比向联结点添加新行要多得多 table。但请记住,在向联结点 table 添加行之前,您需要查询 projectX 的 ID 和 Mary 的 ID,因此即使在这种情况下,您也需要两个查询和一个 Add
自从发现可以使用ICollections后,就很少再使用结点table了。如果你真的想使用它,将它添加到你的 DbContext 中。使用流利的 API 来说明这是项目和员工之间多对多关系的连接点 table。
最后一个例子:创建一个新项目,让没有多少项目的三个最年轻的员工参与其中:
var youngEmployeesWithFewProjects = dbContext.Employees
.Where(employee => employee.Projects.Count <= 3)
.OrderByDesending(employee => employee.Birthday)
.Take(3);
var addedProject = dbContext.Projects.Add(new Project()
{
Name = "Secret Project",
...
Employees = youngEmployeesWithFewProjects.ToList(),
});
我需要一些帮助来查询我的 MVC 应用程序。
我在 SQL 中创建了这个查询:
SELECT Projects.ID, Projects.ProjectName, Employees.ID
FROM Projects INNER JOIN (Employees INNER JOIN ProjectEmployees ON Employees.ID = ProjectEmployees.EmployeeId) ON Projects.ID = ProjectEmployees.ProjectId
WHERE (((Employees.ID)=2));
它应该是这样的:
我如何使用 perahps LinQ 或其他适合我的 MVC 应用程序的格式重建它。
谢谢,卡斯滕
使用 LINQ 看起来像这样
from p in Projects
join pe in ProjectEmployees on p.ID equals pe.ProjectId
join e in Employees on pe.EmployeeID equals e.ID
where e.ID = 2
select new {
ProjectId = p.ID,
ProjectName = p.ProjectName,
EmployeeId = e.ID
}
评论后最后添加
您似乎在员工和项目之间设计了一个简单的多对多关系:每个员工在零个或多个项目上工作,每个项目都由零个或多个员工完成。
如果您遵循了 entity framework coding conventions,您将得到类似于:
class Employee
{
public int Id {get; set;}
public string Name {get; set;}
... // other Employee properties
// every Employee works on zero or more Projects, many-to-many
public virtual ICollection<Project> Projects {get; set;}
}
class Project
{
public int Id {get; set;}
public string Name {get; set;}
... // other Project properties
// every Project is done by zero or more Employees, many-to-many
public virtual ICollection<Employee> Employees {get; set;}
}
为了完整起见,DbContext:
class DbContext
{
public DbSet<Employee> Employees {get; set;}
public DbSet<Project> Projects {get; set;}
}
这就是 entity framework 检测多对多关系所需知道的全部内容。尽管未提及结点 table,但 entity framework 足够聪明,知道这种关系需要结点 table 并会为您创建它。
但是,如果我无法访问连接点 table,我该如何进行(组)加入?
答案:不要自己加入(组),使用虚拟 ICollection。
要求:给我Id为[2]的员工工作的项目(的一些属性)。
const int employeeId = 2;
var employeeWithHisProjects = dbContext.Employees
.Where(employee => employee.Id == 2)
.Select(employee => new
{
// For efficiency, select only the Employee properties that you plan to use:
Id = employee.Id,
Name = employee.Name,
...
Projects = employees.Projects
// Only if you don't want all Projects of Employee[2]:
// for example: Projects with DueDate before today:
.Where(project => project.DueDate <= today)
.Select(project => new
{
// again: only the project properties that you plan to use.
Id = project.Id,
Name = project.Name
...
})
.ToList(),
});
换句话说:从table个Employees中,只保留Id等于2的Employees。从剩下的Employees中,取Id,name和...;从他的项目中,只保留截止日期在今天或之前的那些项目。从剩余的项目中获取 Id、名称和...
Entity framework 知道你的多对多关系,并且足够聪明,可以为你做正确的(组)加入。
看看这感觉有多自然,尤其是如果您将其与您建议的内部联接进行比较?
Inner Join 和 GroupJoin 之间的小区别
请注意,两者之间存在细微差别。如果省略 Where Employee.Id == 2
,内部联接的结果将是:
Employee Project
2 A
2 B
3 A
4 C
3 C
2 C
4 B
使用 ICollection 或进行 GroupJoin 你会得到类似
的东西- 员工[2] 及其项目 A、B、C
- 员工[3] 及其项目 A、C
- 员工[4] 和他的项目 B、C
- 没有任何项目的员工[5]
GroupJoin 给出了更自然的结果。 Employee [2] 的所选属性仅传输一次,即使他有 3 个项目。
更重要的是:您还会看到 Employee[5],即使他没有任何项目!
如何添加员工和项目
您可以在没有任何员工参与的情况下添加项目。您可以添加尚未从事任何项目的员工。
var addedProject = dbContext.Projects.Add(new Project()
{
// Id is filled when you SaveChanges
Name = "Improve Entity FrameWork",
...
// no one is working on this project yet, therefore no need to mention Employees
// or if you want, assign null, or empty collection
Employees = new Employee[],
});
var addedEmployee = dbContext.Employees.Add(new Employee()
{
// Id is filled when you SaveChanges
Name = "John Doe",
...
// John is not working on any Project yet
});
如果您想添加已经在多个项目中工作的员工:
// Select 3 projects suitable for new employees:
var projectsForNewEmployee = dbContext.Projects
.Where(project => project.Difficulty == Difficulty.LearningStage)
.OrderBy(project => project.Priority)
.Take(3);
var employeeWithSomeProjects = dbContext.Employees.Add(new Employee()
{
Name = "Max Rabe",
...
Projects = projectsForNewEmployee.ToList(),
});
假设我们要将员工 "Mary" 添加到项目 "Project X":
var projectX = dbContext.Projects
.Where(project => project.Name == "Project X")
.FirstOrDefault();
var mary = dbContext.Employees
.Where(employee => employee.Name == "Mary")
.FirstOrDefault(),
// Mary gets a new Project:
mary.Projects.Add(projectX);
dbContext.SaveChanges();
您也可以将 Mary 添加到 projectX:
projectX.Employees.Add(mary);
dbContext.SaveChanges();
这似乎比向联结点添加新行要多得多 table。但请记住,在向联结点 table 添加行之前,您需要查询 projectX 的 ID 和 Mary 的 ID,因此即使在这种情况下,您也需要两个查询和一个 Add
自从发现可以使用ICollections后,就很少再使用结点table了。如果你真的想使用它,将它添加到你的 DbContext 中。使用流利的 API 来说明这是项目和员工之间多对多关系的连接点 table。
最后一个例子:创建一个新项目,让没有多少项目的三个最年轻的员工参与其中:
var youngEmployeesWithFewProjects = dbContext.Employees
.Where(employee => employee.Projects.Count <= 3)
.OrderByDesending(employee => employee.Birthday)
.Take(3);
var addedProject = dbContext.Projects.Add(new Project()
{
Name = "Secret Project",
...
Employees = youngEmployeesWithFewProjects.ToList(),
});