2010-05-18 1 views
5

В моем приложении у компании может быть много сотрудников, и у каждого сотрудника может быть несколько адресов электронной почты.Запрос Linq с подзапросом как значения, разделенные запятой

Схема базы данных относится к таблицам, как это:

Компания -> CompanyEmployeeXref -> Сотрудник -> EmployeeAddressXref -> Email

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

 

from c in Company 
join ex in CompanyEmployeeXref on c.Id equals ex.CompanyId 
join e in Employee on ex.EmployeeId equals e.Id 
join ax in EmployeeAddressXref on e.Id equals ax.EmployeeId 
join a in Address on ax.AddressId equals a.Id 
select new { 
       c.Name, 
       a.Email.Aggregate(x=>x + ",") 
      } 
 

Desired Output: 

"Company1", "[email protected],[email protected],[email protected]" 

"Company2", "[email protected],[email protected],[email protected]" 

... 

Я знаю, что этот код не так, я думаю, что я пропускаю группу по, но она иллюстрирует точку. Я не уверен в синтаксисе. Возможно ли это? Спасибо за любую помощь.

+0

У меня есть код, который делает это, но он будет выполнять новую партию для каждой компании в вашем случае. Я отправлю его завтра, если у кого-то есть что предложить. –

ответ

7

Вот теперь я решил проблему:

 

from c in Company 
join ex in CompanyEmployeeXref on c.Id equals ex.CompanyId 
join e in Employee on ex.EmployeeId equals e.Id 
join ax in EmployeeAddressXref on e.Id equals ax.EmployeeId 
join a in Address on ax.AddressId equals a.Id 
group a.Email by new {c.Name} into g 
select new { 
       Company=g.Key.Name, 
       Email=g.Select(e=>e).Distinct() 
      } 
).ToList() 
.Select(l=> 
      new { 
        l.Name, 
        Email=string.Join(",", l.Email.ToArray()) 
       } 
     ) 

 
+0

Вы сделали трассировку на этом, чтобы увидеть, что SQL он использует? –

+0

работал как шарм. благодаря –

5

На самом деле это довольно сложно сделать в чистом Linq to SQL (или Entity Framework, в зависимости от того, что вы используете), поскольку сам SQL Server не имеет какого-либо агрегированного оператора, который может создавать список с разделителями-запятыми, поэтому он имеет невозможно преобразовать весь этот оператор в один запрос. Я мог бы дать вам ответ «один оператор» Linq to SQL, но на самом деле он не даст вам очень хорошую производительность, и я не уверен, что он вообще будет работать в EF.

Это уродливее, но еще лучше, если вы просто регулярно присоединиться, материализуются результаты, а затем сделать свою конкатенацию с помощью Linq к объектам:

var rows = 
    (from c in Company 
    join ex in CompanyEmployeeXref on c.Id equals ex.CompanyId 
    join e in Employee on ex.EmployeeId equals e.Id 
    join ax in EmployeeAddressXref on e.Id equals ax.EmployeeId 
    join a in Address on ax.AddressId equals a.Id 
    select new 
    { 
     c.Name, 
     a.Email 
    }).AsEnumerable(); 

var emails = 
    from r in rows 
    group r by r.Name into g 
    select new 
    { 
     Name = g.Key, 
     Emails = g.Aggregate((x, y) => x + "," + y) 
    };