LINQ to Entities 和空字符串

发布于 2024-12-14 19:08:02 字数 1643 浏览 1 评论 0原文

我在使用 EF 4.0 作为数据库后端的 ASP.NET 4.0 Web 应用程序上发生了一件非常奇怪的事情。本质上,我有一个存储用户密码重置请求的表(包含 byte[] 类型的重置键、DateTime 类型的到期时间和外键包含字符串电子邮件字符串名称用户)。某些用户没有设置电子邮件地址,因此对于 PasswordRequest 请求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;

我'我完全被难住了。有什么想法吗?

I've got quite a strange thing happening on an ASP.NET 4.0 web application using EF 4.0 as its database backend. Essentially, I've got a table that stores users' password reset requests (containing a reset key of type byte[], an expiry of type DateTime, and a foreign key to a User containing a string Email and string Name). Some users do not have an email address set, so for a PasswordRequest request, request.Email is null.

Here's the problem. This works perfectly fine:

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;

I get the expected number of results (nonzero, since there are entries with null emails).

But this always returns an empty collection when e is 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;

The only thing that I got to work properly (which doesn't logically make any sense) is this:

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;

I'm absolutely stumped. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

穿透光 2024-12-21 19:08:02

基本上,这是 SQL 和 C# 在处理空值方面的不匹配。您不需要使用两个查询,但您需要:

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。

如果您对以相同方式处理 null 和空字符串感到满意,您至少可以尝试一个小技巧是:

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

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

我相信这将在电子邮件列和 e< 上执行 null 合并/code>,所以你永远不会将 null 与任何东西进行比较。

Basically this is a mismatch between SQL and C# when it comes to the handling of nulls. You don't need to use two queries, but you need:

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

It's annoying, and there may be a helper function to make life easier, but it fundamentally comes from SQL's null handling where

where X = Y

will not match if both X and Y are null. (Whereas in C# the equivalent expression would be true.)

You may need to do the same for u as well, unless that is non-nullable in the database.

One small trick you could at least try if you're happy with null and empty strings being handled the same way is:

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

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

I believe that will perform null coalescing on both the email column and e, so you never end up comparing null with anything.

望笑 2024-12-21 19:08:02

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

这里:

LINQ 语法,其中字符串值不为 null 或空

LINQ to SQL 和空字符串,如何使用 Contains?

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

I have found a couple of articles detailing the same issue. Unfortunately, I haven't faced this issue so far. It is very interesting though.

Here:

LINQ syntax where string value is not null or empty

LINQ to SQL and Null strings, how do I use Contains?

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

南薇 2024-12-21 19:08:02

如果您像我一样更喜欢使用方法(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;

If you prefer using method (lambda) syntax as I do, you could do it like this:

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;
回首观望 2024-12-21 19:08:02

如果您想在 request['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 和 is null 是不同的。参见--> MSDN Info

因此,您的最后一个示例是有效的,因为您需要 2从数据库获取数据的方法。即如果 email 为 null 则为 1,如果 email == Request['e'] 则为 1

If you want to retrieve items from the DB when request['e'] == null

it should have been

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

note that == null and is null is different . see --> MSDN Info

Therefore, your last example is sort of valid since you need 2 ways to get data from the DB. i.e. one if email is null and one if email == Request['e']

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文