Запрос внутреннего соединения в EF6 - PullRequest
0 голосов
/ 03 апреля 2020


Мне нужна помощь с запросом для моего 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));

Он должен выглядеть следующим образом: Access Querydesigner

Как я могу восстановить это, используя perahps LinQ или другой подходящий формат для моего MVC -приложения.

Спасибо, Карстен

Ответы [ 2 ]

2 голосов
/ 03 апреля 2020

При использовании 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
            }
1 голос
/ 03 апреля 2020

Добавление в конце после комментария

Кажется, вы разработали прямое отношение «многие ко многим» между сотрудниками и проектами: каждый сотрудник работает с нулевым или большим количеством проектов, и каждый проект выполнен ноль или более сотрудников.

Если вы следовали соглашениям по кодированию структуры сущностей , у вас будет что-то похожее на:

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;}
}

Это все, что должна знать структура сущностей, чтобы обнаружить ваши отношения «многие ко многим». Несмотря на то, что таблица соединений не упоминается, структура сущностей достаточно умна, чтобы знать, что такого рода отношения нуждаются в таблице соединений и создаст ее для вас.

Но как мне это сделать (group- ) присоединиться, если у меня нет доступа к соединительной таблице?

Ответ: Не присоединяйтесь (группа-) самостоятельно, используйте виртуальную коллекцию ICollection.

Требование: Дайте (некоторые свойства) проекты, над которыми работает Сотрудник с идентификатором [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(),
    });

Словами: из таблицы Сотрудников сохраняйте только сотрудники с Id, равным 2. Из оставшихся сотрудников возьмите Id, имя и ...; из его проектов, оставляйте только те проекты с установленным сроком исполнения или до сегодняшнего дня. Из оставшихся проектов возьмите Id, Name и ...

Платформа сущностей знает ваше отношение «многие ко многим» и достаточно умна, чтобы сделать правильное (групповое) соединение для вас.

Посмотрите, как это естественно, особенно если сравнить это с предлагаемыми внутренними объединениями?

Небольшая разница между внутренним объединением и GroupJoin

Обратите внимание, что есть небольшая разница. Если вы пропустите Where Employee.Id == 2, результатом внутреннего соединения будет:

Employee  Project
   2         A
   2         B
   3         A
   4         C
   3         C
   2         C
   4         B

Используя ICollection или GroupJoin, вы получите что-то вроде

  • Employee [ 2] с его проектами A, B, C
  • Сотрудник [3] с его проектами A, C
  • Employee [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(),
});

Предположим, что мы хотим Добавить сотрудника "Мэри" в проект "Проект 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();

Вы также можете добавить Мэри в projectX:

projectX.Employees.Add(mary);
dbContext.SaveChanges();

Кажется, что это больше, чем просто добавить Новая строка в соединительной таблице. Но помните, что прежде чем вы сможете добавить строку в таблицу соединений, вам нужно запросить Id для ProjectX и Id для Mary, поэтому даже в этом случае вам потребуется два запроса и один Add

, так как я обнаружил, что Я могу использовать ICollections, я редко использую соединительную таблицу больше. Если вы действительно хотите использовать его, добавьте его в свой DbContext. Используйте свободный API, чтобы сказать, что это соединительная таблица для отношения «многие ко многим» между проектами и сотрудниками.

Один последний пример: создайте новый проект и позвольте трем самым молодым сотрудникам, у которых не так много проектов, работать на нем:

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(),
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...