2011-11-11 173 views
13

我在使用EF 4.0作为数据库后端的ASP.NET 4.0 Web应用程序上发生了一件奇怪的事情。基本上,我有一张表,用于存储用户的密码重置请求(包含类型为byte[]的重置密钥,类型DateTime到期,以及包含string Emailstring NameUser的外部密钥)。某些用户没有设置电子邮件地址,因此对于PasswordRequest requestrequest.EmailnullLINQ to Entities和空字符串

这是问题所在。这工作完全正常:

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; 

我绝对难住。有任何想法吗?

+0

的电子邮件字段在你的实际表中,是否声明为NULL列? – DoomerDGR8

+0

@HassanGulzar确实如此。 – hydroiodic

+0

你能发布生成的sql吗? – Marius

回答

33

基本上这是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,所以你永远不会比较null与任何东西。

+1

啊哈!我虽然可能会这样做,但我不确定究竟是什么造成了这一点。谢谢澄清! – hydroiodic

+0

+1了解如此快速和回答 –

+0

很好地完成!哪里的情况有点松动。所以我想把'e'的所有三个可能的值都说得通。 – DoomerDGR8

-1

如果你想要从数据库时要求[ '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种方法从数据库中获取数据。即如果一个电子邮件为null,一个有邮箱==请求[“E”]

0

如果您更喜欢使用方法(拉姆达)语法像我一样,你可以做这样的:

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;