Linq-to-Entities: LEFT OUTER JOIN с предложением WHERE, расчет и проекция

Мне очень трудно понять, как перевести простое SQL LEFT OUTER JOIN на несколько столбцов и предложение where в рабочий запрос Linq-to-Entities. Есть только две таблицы. Мне нужны значения для всех строк из Table1, независимо от совпадений в Table2, но объединение нескольких столбцов оказывается трудным. Мне также нужно сделать простой расчет в запросе, но могуНе могу найти это тоже. Запрос в SQL будет выглядеть так:

select t1.tableid1,
t1.tableid2,
t1.fieldvalue1,
t2.fieldvalue2,
isnull(t2.fieldvalue2,0) / t1.fieldvalue1 as calcvalue
t1.fieldvalue1 - isnull(t2.fieldvalue2,0) as calcvalue2
from table1 t1
left outer join table2 t2 
    on t1.tableid1 = t2.tableid1
    and t1.tableid2 = t2.tableid2
    and t1.tableid3 = t2.tableid3
where t1.tableid1 = @somevalue

Я могу сделать одно соединение слева, но я могуПохоже, что он нашел правильный синтаксис для нескольких столбцов, не говоря уже о том, что он не знает, как добавить или вычесть значения в столбце. Ниже мое лучшее предположение, но яполучаю ошибку ожидаемого типа (после "новый» и перед первой открывающей скобкой) для:

On New (t2.Field(Of String)("tableid1"), t2.Field(Of String)

Лучшая догадка:

Dim query = From t1 In dtTable1 _
                         Group Join t2 In dtTable2 _
                         On New (t2.Field(Of String)("tableid1"), t2.Field(Of String)("tableid2")) Equals _
                            (t1.Field(Of String)("tableid1"), t1.Field(Of String)("tableid2")) _
                         Into t2outer = Group _
                         From t2 In t2outer.DefaultIfEmpty() _
                         Select New With _
                        { _
                            .t1_tableid1 = t1.Field(Of String)("tableid1"), _
                            .t1_tableid2 = t1.Field(Of String)("tableid2"), _
                            .t1_fieldvalue1 = t1.Field(Of Integer)("fieldvalue1"))
                            .t2_fieldvalue2 = If(t2 Is Nothing, CType("0", Integer), t2.Field(Of Integer)("fieldvalue2"))
                        }

@Gert Это подобрало меня достаточно близко. Я думаю, что форматирование было немного отключено, так как я должен был добавить фигурные скобки, а не круглые скобки, и он поместил пробел между "Ключ» Ключевое слово и идентификатор:

On New With {
                        Key .id1 = t2.Field(Of String)("tableid1"), _
                        Key .id2 = t2.Field(Of String)("tableid2")
                        } _
                    Equals _
                    New With {
                        Key .id1 = t1.Field(Of String)("tableid1"), _
                        Key .id2 = t1.Field(Of String)("tableid2")
                        } _

Благодаря Герту я смог заставить это работать, как описано в запросе SQL. Ниже показано, какое должно быть полное рабочее представление SQL-запроса:

Dim query = From t1 In dtTable1 _
    Where (T1.Field(Of String)("fieldvalue1") = SOMEVALUE) _
     Group Join t2 In dtTable2 _
     On New (t2.Field(Of String)("tableid1"), t2.Field(Of String)("tableid2")) Equals _
        (t1.Field(Of String)("tableid1"), t1.Field(Of String)("tableid2")) _
     Into t2outer = Group _
     From t2 In t2outer.DefaultIfEmpty() _
     Select New With _
    { _
        .t1_tableid1 = t1.Field(Of String)("tableid1"), _
        .t1_tableid2 = t1.Field(Of String)("tableid2"), _
        .t1_fieldvalue1 = t1.Field(Of Integer)("fieldvalue1"))
        .t2_fieldvalue2 = If(t2 Is Nothing, CType("0", Integer), t2.Field(Of Integer)("fieldvalue2"))
        .calcvalue = If(t2.Field(Of Integer)("fieldvalue2") Is Nothing, CType("0", Integer), t2.Field(Of Integer)("fieldvalue2")) _
            / CType(t1.Field(Of String)("fieldvalue1"), Integer), 
        .calcvalue2 = CType(t1.Field(Of String)("fieldvalue1"), Integer) _
            - If(t2.Field(Of Integer)("fieldvalue2") Is Nothing, CType("0", Integer), t2.Field(Of Integer)("fieldvalue2")) _
    }

Ответы на вопрос(2)

Решение Вопроса

если вы группируете по нескольким полям, вы сравниваете анонимные типы, поэтому часть

On
   New (t2.Field(Of String)("tableid1"), t2.Field(Of String)("tableid2"))
Equals
       (t1.Field(Of String)("tableid1"), t1.Field(Of String)("tableid2"))

должен быть изменен на синтаксис для создания анонимных типов (так же, как вы используете позже в запросе):

On
  New With {.id1 = t2.Field(Of String)("tableid1"),
            .id2 = t2.Field(Of String)("tableid2")}
Equals
  New With {.id1 = t1.Field(Of String)("tableid1"),
            .id2 = t1.Field(Of String)("tableid2")}

но

В C # этого было бы достаточно, потому что с анонимными типами компилятор C # использует равенство, основанное наценности, По некоторым причинам, однако, с VB это отличается, он используетссылка равенство. ИтакEquals всегдаfalseпотому что первый объект не является тем же объектом, что и второй.

К счастью, VB имеетKey Ключевое слово, которое позволяет указать свойства, которые будут использоваться при сравнении анонимных объектов. Итак, последний синтаксис:

On
  New With {Key .id1 = t2.Field(Of String)("tableid1"),
            Key. id2 = t2.Field(Of String)("tableid2")}
Equals
  New With {Key .id1 = t1.Field(Of String)("tableid1"),
            Key .id2 = t1.Field(Of String)("tableid2")}
 user216233123 июн. 2013 г., 21:28
Это дало мне достаточно близко. Я думаю, что форматирование было немного выключено,
 user216233123 июн. 2013 г., 21:37
Огромное спасибо, что достало меня достаточно близко (см. Мой исправленный оригинальный пост). Я считаю, что форматирование может быть немного отключен для vb.net? Теперь, где я должен добавить мое предложение WHERE, так как оно мне нужно, чтобы возможно отфильтровать и table1, и table2 (если оно существует). И возможно ли вообще выполнять простые вычисления в запросе ссылки? т.е. t1.FieldValue1 - t2.FieldValue2 = CalculatedValue1
 Gert Arnold23 июн. 2013 г., 21:47
Обычно для вложенныхWheres самый удобный способ - это смешать синтаксис запроса с синтаксисом беглого (метода):,dtTable1.Where(...)Group Join t2 In dtTable2.Where(...), И, конечно же, вы можете поместить рассчитанные свойства в проекции (=Select), но они должны выглядеть..t1_fieldvalue1 = t1.Field(...) - t1.Field(...)
 user216233123 июн. 2013 г., 22:21
Работал абсолютно блестяще. Большое спасибо. Я'm добавив полный код к исходному сообщению, чтобы помочь кому-либо в будущем. Еще раз спасибо Герт!

Это условие позволяет фильтровать результаты по значению полей и объединять их с другими значениями. Части в {} предназначены для вас, чтобы изменить их в соответствии с вашими сущностями. Этот запросIEnumerable(Of {your entity})- отлично подходит для привязки данных.

Dim query = model.{table name}.Where(Function(o) o.{column name} = {some value}).ToList()
 OneFineDay23 июн. 2013 г., 05:28
Если вы создадите отношения в БД до того, как создадите модель, у вас будетnavigation properties, Здесь вы получаете доступ к связанной таблицеtable name а такжеfield, Пример: если таблицаCustomer относится кOrders у вас будет свойство как:Customers.Orders.OrderId и может использовать это в фильтре запросов выше.
 user216233123 июн. 2013 г., 04:24
я в замешательстве ... тогда я могу заставить работать внешнее соединение, если оноОдин столбец, но как только я добавлю несколько столбцов, это приведет к ошибкам. Не могли бы вы уточнить, используя мой пример? Я думал попробовать: "On New (t2.Field (Of String) ("tableid1"), t2.Field (Of String) ("tableid2")) Равно немного после прочтения нескольких запросов c # linq. Я надеялся, что синтаксис мог бы быть несколько похожим.

Ваш ответ на вопрос