Подтвердить что ты не робот

LINQ to Entities и нулевые строки

У меня довольно странная вещь, происходящая в веб-приложении ASP.NET 4.0 с использованием EF 4.0 в качестве базы данных. По существу, у меня есть таблица, в которой хранятся пароли пользователей reset (содержащий reset ключ типа byte[], истечение срока действия DateTime и внешний ключ , содержащий a 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;

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

4b9b3361

Ответ 1

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

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

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

where X = Y

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

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

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

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

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

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

Ответ 2

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

Здесь:

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

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

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

Ответ 3

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

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;

Ответ 4

Если вы хотите получить элементы из БД при запросе ['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

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