LINQ to Entity: условия множественного соединения

Существует множество сообщений о LINQ и нескольких соединениях. Я, однако, не нашел решения для присоединения, которое я хотел бы сделать.

Эквивалент SQL будет примерно таким:

SELECT * FROM table1 a
LEFT JOIN table2 b ON a.col1 = b.key1 AND
a.col2 = b.key2 AND
b.from_date <= now() AND
b.deleted = 0;

Здесь один из многочисленных запросов linq, которые я пытался

var query = (from x in context.table1
             join y in context.table2 on new {x.col1, x.col2} equals {b.key1, b.key2} 
             into result
             from result......

Как добавить дополнительные условия даты и удалить флаг? Если я использую условия. В этом случае это рассматривается как внутреннее соединение, а не левое соединение.

Ответ 1

Другой способ может быть подобен

var query = (from x in context.table1 
             join y in context.table2 on 
             new  {
                  Key1 = x.col1, 
                  Key2 = x.col2
                  Key3 = true,
                  Key4 = true
                 }
             equals
             new {
                  Key1 = y.key1, 
                  Key2 =  y.key2,
                  Key3 = y.from_date< DateTime.Now,
                  Key4 = !y.deleted
                 }  
             into result
from r in result.DefaultIfEmpty()
select new  {x.Something, r.Something}

Ответ 2

LINQ поддерживает синтаксис соединения и более старый синтаксис ANSI-82 WHERE. Используя позже, вы можете делать то, с чем вы смотрите

var nowTime = DateTime.Now;
var query = from a in context.table1
            from b in context.table2
            where a.col1 == b.key1
                 && a.col2 == b.key2 
                 && b.from_date < nowTime
                 && b.deleted == false
            select ???;

Кроме того, вы можете использовать гибрид, где и присоединиться. (Реализуйте, что порядок в запросе LINQ не должен имитировать то, что вы бы сделали в SQL, и порядок более гибкий.)

var nowTime = DateTime.Now;
var query = from b in context.table2
            where b.from_date < nowTime
                 && b.deleted == false
            join a on new {b.key1, b.key2} equals new {a.col1, a.col2}
            select ???;

Ответ 3

Не могли бы вы просто отфильтровать первый результирующий набор со вторым запросом?

var query = (from x in context.table1 
             join y in context.table2 on new {x.col1, x.col2} equals {b.key1, b.key2}  
             into result
query = from x in query
        where ...

Будет ли это работать?

Ответ 4

У меня возникла проблема с именем свойств в анонимном объекте:

var subscriptions = context.EmailSubscription.Join(context.EmailQueue,
                    es => new { es.Id, 9 },
                    eq => new { eq.EmailSubscriptionId, eq.EmailTemplateId },
                    (es, eq) => new { es.Id, eq.Id }
                ).ToList();

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

var subscriptions = context.EmailSubscription.Join(context.EmailQueue,
                    es => new { EmailSubscriptionId = es.Id, EmailTemplateId  = 9 },
                    eq => new { eq.EmailSubscriptionId, eq.EmailTemplateId },
                    (es, eq) => new { es.Id, eq.Id }
                ).ToList();