2016-02-09 2 views
2

У меня есть отношения между Users и UsersProjects. UserProjects.UserId ссылки на Users.UserIdLINQ Union vs SQL Union

Я хочу, чтобы найти пользователя, который находится в UserProjects и UserProject имеет UsreProjects.ProjectId == 4. Затем присоедините остальных пользователей к этой таблице.

На самом деле я хочу изменить некоторые свойства пользователя, который UserProject = 4.

В MSSQL, просто чтобы проверить меня ниже запроса

Select U.UserId 
from Users U 
Join UserProjects UP 
On U.UserId = up.UserId 
Where up.ProjectId = 4 
Union 
Select U.UserId From Users U 

Я не изменять любые свойства. Во всяком случае, в результате он показывает мне всех пользователей, как и должно быть.

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

var usrs = ((from users in context.Users 
          join userProj in context.UserProjects 
          on users.UserId equals userProj.UserId 
          where userProj.ProjectId == projectId 
          select new ProjectUsersDTO 
          { 
           UserName = users.Name, 
           Rate = users.RatePerHour, 
           UserId = users.UserId, 
           alreadyInProject = true 
          }) 
          .Union(from users in context.Users 
            select new ProjectUsersDTO 
            { 
             UserName = users.Name, 
             Rate = users.RatePerHour, 
             UserId = users.UserId, 
             alreadyInProject = false 
            })) 
           .ToList(); 
        return usrs; 

Как это происходит, когда UNION не допускает дубликатов?

Спасибо за внимание!

+0

Вашего LINQ союз должен привести к уникальным объектам до тех пор, как объекты сопоставимы и равны. Ваши объекты являются ProjectUsersDTO. Я думаю, вам нужно будет реализовать интерфейс IEquatable для этого объекта, чтобы профсоюз работал так, как вы планируете. Кроме того, ваши значения немного отличаются, поскольку свойства «ужеInProject» [sic] не идентичны. Если ваша реализация IEquatable игнорирует это свойство, это не имеет значения. –

+1

Вы используете IEnumerable.Union, поскольку вы проектируете DTO перед объединением. Если вы хотите, чтобы отчет выполнялся с помощью базы данных, вам нужно отложить проецирование на DTO до момента объединения. Поэтому создайте анонимный тип в обоих запросах, затем в объединении, затем добавьте вызов AsEnumerable(), затем выполните проект в DTO, затем выполните ToList(). – Maarten

+0

@Maarten Я как раз собирался добавить это. –

ответ

2

LINQ Union против SQL Союза

Они эквивалентны.

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

Это не то же самое запрос. В первом (SQL) запросе вы выбираете (включаете) только одно поле (UserId), а во втором (LINQ) вы включаете пару полей, один из которых является точно разными.Так как Union использует все включенные поля в качестве критерия, является ли элемент уникальным, нормальным является второй запрос для возврата большего количества элементов.

С учетом сказанного давайте посмотрим, как решить конкретную проблему. Похоже, вам не нужен Union. Как правило, вы должны иметь навигационных свойства, поэтому простой запрос, как это должно сделать работу (при условии, навигационное свойство называется Projects):

var query = 
    from user in context.Users 
    select new ProjectUsersDTO 
    { 
     UserName = user.Name, 
     Rate = user.RatePerHour, 
     UserId = user.UserId, 
     alreadyInProject = user.Projects.Any(userProj => userProj.ProjectId == projectId) 
    }; 

var result = query.ToList(); 
2

Разность между поведением SQL UNION (который выполняет неявное DISTINCT) и LINQ Union (которые требуют явного Distinct()) объясняется here.

Итак, для вашего конкретного случая, примените к вашему запросу Distinct().

+0

Указанная вами ссылка не объясняет различия вообще. В нем говорится об использовании linq, а не ef или l2s. – Maarten

0

Уникальность/отсутствие дубликатов основано на полной записи/экземпляре ProjectUsersDTO.

Пользователи в проекте 4 (или что бы то ни было значение для переменной projectId) будут дважды в результате, одно время с ужеInProject = true и другое время с ужеInProject = false. Первый выбор выбирает только пользователей в проекте, а второй выбирает всех пользователей (включая те, что указаны в проекте). Они рассматриваются как разные записи, потому что значение для ужеInProject отличается, поэтому обе версии будут на выходе.

Я не уверен, что вы хотите, но я предполагаю, что вам нужен список всех пользователей с указанием, являются ли они в проекте с данным проектомId. Вы можете использовать этот код

var usrs = (from users in context.Users 
      join userProj in context.UserProjects 
      on users.UserId equals userProj.UserId 
      select new ProjectUsersDTO 
      { 
       UserName = users.Name, 
       Rate = users.RatePerHour, 
       UserId = users.UserId, 
       alreadyInProject = (userProj.ProjectId == projectId) 
      }) 
      .ToList(); 
return usrs;