LINQ到实体和空字符串

本文关键字:字符串 实体 LINQ | 更新日期: 2023-09-27 18:14:03

在ASP上发生了一件很奇怪的事情。NET 4.0 web应用程序,使用EF 4.0作为其数据库后端。基本上,我有一个存储用户密码重置请求的表(包含类型为byte[]的重置键、类型为DateTime的到期键和包含string Emailstring NameUser的外键)。有些用户没有电子邮件地址集,所以对于PasswordRequest request, request.Emailnull

问题在这里。

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电子邮件的条目)。

但是当enull时,这总是返回一个空集合:

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;
我完全被难住了。什么好主意吗?

LINQ到实体和空字符串

基本上这是SQL和c#在处理null时的不匹配。您不需要使用两个查询,但您需要:

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

这很烦人,可能会有一个辅助函数来简化工作,但它基本上来自SQL的null处理,其中

where X = Y
如果X和Y都为空,

不匹配。(而在c#中,等效表达式将为true。)

您可能也需要为u做同样的事情,除非它在数据库中是非空的。

一个小技巧,你至少可以尝试如果你喜欢null和空字符串以同样的方式处理:

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

我相信这将在email列和e上执行null合并,因此您永远不会将null与任何内容进行比较。

我找到了几篇详细介绍相同问题的文章。不幸的是,到目前为止我还没有遇到过这个问题。但它很有趣。

:

LINQ语法,字符串值不是null或空

LINQ SQL和空字符串,我如何使用包含?

from MSDN: http://msdn.microsoft.com/en-us/library/bb882535.aspx

如果您像我一样喜欢使用method (lambda)语法,您可以这样做:

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;

如果您想在request['e'] == null时从DB检索项

应该是

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

注意== null和is的null是不同的。见--> MSDN信息

因此,你的最后一个例子是有效的,因为你需要2种方式从数据库获取数据。也就是说,如果email为null,如果email == Request['e']