LINQ to Entities и нулевые строки - PullRequest
15 голосов
/ 11 ноября 2011

У меня довольно странная вещь, происходящая в веб-приложении ASP.NET 4.0, использующем EF 4.0 в качестве базы данных.По сути, у меня есть таблица, в которой хранятся запросы пользователей на сброс пароля (содержащие ключ сброса типа byte[], срок действия типа DateTime и внешний ключ для User, содержащий string Email и string Name).У некоторых пользователей не установлен адрес электронной почты, поэтому для PasswordRequest request, request.Email равно null.

Вот проблема.Это прекрасно работает:

string u = Request["u"];
string e = Request["e"];

var requests = from r in context.PasswordRequests
               where r.User.Name == u && r.User.Email == null && r.Expiry >= DateTime.Now
               select r;

Я получаю ожидаемое количество результатов (ненулевое значение, поскольку есть записи с null электронными письмами).

Но это всегда возвращает пустую коллекцию, когда e это null:

string u = Request["u"];
string e = Request["e"];

var requests = from r in context.PasswordRequests
               where r.User.Name == u && r.User.Email == e && r.Expiry >= DateTime.Now
               select r;

Единственное, что мне нужно, чтобы работать должным образом (что не имеет никакого логического смысла), это:

string u = Request["u"];
string e = Request["e"];

IQueryable<PasswordRequest> requests;

if (e == null)
    requests = from r in context.PasswordRequests
               where r.User.Name == u && r.User.Email == null && r.Expiry >= DateTime.Now
               select r;
else
    requests = from r in context.PasswordRequests
               where r.User.Name == u && r.User.Email == e && r.Expiry >= DateTime.Now
               select r;

Яабсолютно в тупик.Есть идеи?

Ответы [ 4 ]

35 голосов
/ 11 ноября 2011

По сути, это несоответствие между SQL и C #, когда дело доходит до обработки нулей.Вам не нужно использовать два запроса, но вам нужно:

where r.User.Name == u && (r.User.Email == e ||
                           (e == null && r.User.Email == null))

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

where X = Y

будет не совпадать, если X и Y равны нулю.(Принимая во внимание, что в C # эквивалентное выражение будет истинным.)

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

Один маленькийтрюк, который вы могли бы по крайней мере попробовать , если вы довольны тем, что нулевые и пустые строки обрабатываются одинаково:

// Before the query
e = e ?? "";

// In the query
where r.User.Name == u && (r.User.Email ?? "") == e

Я считаю, что это выполнит объединение нулей для обоих столбцов электронной почтыи e, так что вы никогда не закончите сравнение нуля с чем-либо.

3 голосов
/ 11 ноября 2011

Я нашел пару статей, подробно описывающих эту проблему. К сожалению, я до сих пор не сталкивался с этой проблемой. Хотя это очень интересно.

Здесь:

Синтаксис LINQ, где строковое значение не является нулевым или пустым

LINQ to SQL и строки Null, как мне использовать Contains?

А из MSDN: http://msdn.microsoft.com/en-us/library/bb882535.aspx

1 голос
/ 04 мая 2016

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

var result = new TableName();

using(var db = new EFObjectContext)
{
    var query = db.TableName;

    query = value1 == null 
        ? query.Where(tbl => tbl.entry1 == null) 
        : query.Where(tbl => tbl.entry1 == value1);

    query = value2 == null 
        ? query.Where(tbl => tbl.entry2 == null) 
        : query.Where(tbl => tbl.entry2 == value2);

    result = query
        .Select(tbl => tbl)
        .FirstOrDefault();

   // Inspect the value of the trace variable below to see the sql generated by EF
   var trace = ((ObjectQuery<REF_EQUIPMENT>) query).ToTraceString();

}

return result;
0 голосов
/ 11 ноября 2011

Если вы хотите получить элементы из БД при запросе ['e'] == null

, это должно было быть

var requests = from r in context.PasswordRequests
               where r.User.Name == u && r.User.Email is null && r.Expiry >= DateTime.Now
               select r;

, обратите внимание, что == null и nullразные .см. -> MSDN Info

Таким образом, ваш последний пример является верным, поскольку вам нужно 2 способа получить данные из БД.т.е. один, если адрес электронной почты равен нулю, и один, если адрес электронной почты == Запрос ['e']

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...