2009-07-07 5 views
5

Есть много вопросов о SO уже о левых соединениях в Linq, и те, которые я просматривал, используют ключевое слово join для достижения желаемого конца.Слева присоединиться к Linq?

Это не имеет смысла для меня. Предположим, у меня есть таблицы Customer и Invoice, связанные внешним ключом CustomerID на Invoice. Теперь я хочу запустить отчет, содержащий информацию о клиенте, а также любые счета-фактуры. SQL будет:

select c.*, i.* 
    from Customer c 
    left join Invoice i on c.ID = i.CustomerID 

Из того, что я видел из ответов на SO, люди в основном предполагает:

var q = from c in Customers 
     join i in Invoices.DefaultIfEmpty() on c.ID equals i.CustomerID 
     select new { c, i }; 

Я действительно не понимаю, как это может быть единственным способом. Связь между Customer и Invoice уже определена классами LinqToSQL; почему я должен повторить его для предложения join? Если бы я хотел получить внутреннее соединение, это было бы просто:

var q = from c in Customers 
     from i in c.Invoices 
     select new { c, i }; 

без указания объединенных полей!

Я пробовал:

var q = from c in Customers 
     from i in c.Invoices.DefaultIfEmpty() 
     select new { c, i }; 

но только дал мне тот же результат, как если бы это было внутреннее соединение.

Нет ли лучшего способа сделать это?

ответ

5

О чем вы говорите? То, что from i in c.Invoice.DefaultIfEmpty() - это точно левое соединение.

 List<string> strings = new List<string>() { "Foo", "" }; 

     var q = from s in strings 
       from c in s.DefaultIfEmpty() 
       select new { s, c }; 

     foreach (var x in q) 
     { 
      Console.WriteLine("ValueOfStringIs|{0}| ValueOfCharIs|{1}|", 
       x.s, 
       (int)x.c); 
     } 

Этот тест производит:

ValueOfStringIs|Foo| ValueOfCharIs|70| 
ValueOfStringIs|Foo| ValueOfCharIs|111| 
ValueOfStringIs|Foo| ValueOfCharIs|111| 
ValueOfStringIs|| ValueOfCharIs|0| 
+1

Ну удар меня - ты прав! Теперь, почему я думал, что это не работает ...? Хорошо, я смиренно отступаю ... этот вопрос возник из-за моего собственного недоразумения. БЛАГОДАРЯ! :) –

2

Возможно, вы захотите использовать ключевое слово 'в'.

Example

+0

Спасибо, но это не реально ответить на мой вопрос ... это не лучший способ, пользуясь тем, что отношения уже определены? –

6

В то время как отношения уже определены (как в базе данных и в DBML-разметке) во время выполнения не может автоматически определить, должен ли он использовать эти отношения.

Что делать, если в объектной модели есть две связи (у человека есть родители и дети, оба отношения с другими экземплярами Person). В то время как случаи могут быть специальными, это сделает систему более сложной (так больше ошибок). Помните, что в SQL вы должны повторить спецификацию отношений.

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

Если вы хотите LEFT OUTER JOIN, то вам нужно использовать "into":

from c in Customers 
join i in Invoices on i.CustomerId equals c.CustomerId into inv 
... 

и и будут иметь тип IEnumerable<Invoivce>, возможно, без каких-либо случаев.

+0

+1 Хороший ответ, но вы по-прежнему не хватает моей точки.В счете-фактуре определенно определено отношение «Клиенты», и я хочу использовать отношения THAT: «c.Invoices», а не только «Счета-фактуры». Есть ли способ сделать это? –

+0

@Shaul: Тогда сделайте так, просто используйте c.Invoices в выражении. Если вы хотите использовать другой идентификатор, используйте предложение let. – Richard

Смежные вопросы