VB.Net Различия в дереве выражений по сравнению с C #

#c# #vb.net #linq

#c# #vb.net #linq

Вопрос:

У меня есть запрос LINQ, который текстуально очень похож как на C #, так и VB.net . Я пытаюсь загрузить все заказы из базы данных Northwind с помощью BLToolkit. Это мой класс Order. Обратите внимание, что OrderDate DateTime является обнуляемым DateTime .

 [TableName("Orders")]
public class Order : EntityBase<int>
{
    public int OrderID;
    public DateTime? OrderDate;
}
 

Код C # linq является:

 from ord in Order
where ord.OrderDate == new DateTime(1997, 11, 14)
select ord.OrderID
 

Код VB linq является:

 From order In db.Order _
Where order.OrderDate = #11/14/1997#
Select order.OrderID
 

При выполнении код C # генерирует это дерево выражений:

 .Call System.Linq.Queryable.Select(
    .Call System.Linq.Queryable.Where(
        .Constant<BLToolkit.Data.Linq.Table`1[Data.Linq.Model.Northwind Order]>(Table(Order)),
        '(.Lambda #Lambda1<System.Func`2[Data.Linq.Model.Northwind Order,System.Boolean]>)),
    '(.Lambda #Lambda2<System.Func`2[Data.Linq.Model.Northwind Order,System.Int32]>))

.Lambda #Lambda1<System.Func`2[Data.Linq.Model.Northwind Order,System.Boolean]>(Data.Linq.Model.Northwind Order $order) {
    $order.OrderDate == (System.Nullable`1[System.DateTime]).New System.DateTime(
        1997,
        11,
        14)
}

.Lambda #Lambda2<System.Func`2[Data.Linq.Model.Northwind Order,System.Int32]>(Data.Linq.Model.Northwind Order $order) {
    $order.OrderID
}
 

и код VB генерирует это дерево выражений:

 .Call System.Linq.Queryable.Select(
    .Call System.Linq.Queryable.Where(
        .Constant<BLToolkit.Data.Linq.Table`1[Data.Linq.Model.Northwind Order]>(Table(Order)),
        '(.Lambda #Lambda1<System.Func`2[Data.Linq.Model.Northwind Order,System.Boolean]>)),
    '(.Lambda #Lambda2<System.Func`2[Data.Linq.Model.Northwind Order,System.Int32]>))

.Lambda #Lambda1<System.Func`2[Data.Linq.Model.Northwind Order,System.Boolean]>(Data.Linq.Model.Northwind Order $order) {
    $order.OrderDate == (System.Nullable`1[System.DateTime]).New System.DateTime(
        1997,
        11,
        14) ?? False
}

.Lambda #Lambda2<System.Func`2[Data.Linq.Model.Northwind Order,System.Int32]>(Data.Linq.Model.Northwind Order $order) {
    $order.OrderID
}
 

Почему VB придерживается ?? False конца сравнения OrderDate и какое значение это имеет?

Отчет о связанной проблеме в BLToolkit

Комментарии:

1. Из любопытства, почему? У вас возникли проблемы с одной работой, а не с другой?

2. Да, BLToolkit — это ORM, который преобразует запрос LINQ в запрос SQL. Он не обрабатывает ?? False то, что вставляет VB.

3. Вы пробовали New DateTime(...) использовать его в версии VB?

4. Да, он генерирует очень похожее дерево выражений, все еще содержащее ?? False .

Ответ №1:

VB.NET обрабатывает обнуляемые типы немного иначе, чем C #, поэтому VB.NET может быть обратно совместим с VB6.

Значение null в C #, равное Null, является фактическим Null и преобразует его в LINQ в SQL.

VB с нулевым значением, то есть Nothing, имеет значение по умолчанию, определенное внутренне, поскольку VB6 не имеет истинного значения «NULL». Свойство поля с нулевым значением «.Value» ничего не возвращает, если внутренним значением является это значение по умолчанию, в то время как LINQ использует внутреннее значение напрямую.

Тот самый «?? False» — это способ LINQ обрабатывать это свойство «На самом деле не является нулевым», поэтому LINQ to Objects не подходит при использовании типов с нулевым значением. Это не переводится в SQL.

В запросах VB LINQ to SQL, использующих типы с нулевым значением, вы должны связать обычное предложение Where с полем «IsNot Nothing» или «».Проверка «Имеет значение». Это позволяет избежать того, чтобы LINQ неявно создавал проверку «является ли это нулевым».

Пример:

 Dim result = From row In Table _
             Where row.nullableField.HasValue AndAlso row.nullableField = someValue _
             Select row
 

Или

 Dim result = From row In Table _
             Where row.nullableField IsNot Nothing AndAlso row.nullableField = anotherValue _
             Select row
 

Комментарии:

1. Потрясающе, именно то, что мне нужно было знать. В LINQ to SQL он не переводится в окончательный SQL, однако я имею дело с ORM, отличным от MS, с открытым исходным кодом, BLToolkit. Похоже, ошибка в том, что они не обрабатывают странную обработку VB с нулевым значением. Очки для вас!