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(),
});