2011-11-11 37 views
13

Tôi đã có một điều khá lạ xảy ra trên một ứng dụng web ASP.NET 4.0 sử dụng EF 4.0 làm cơ sở dữ liệu phụ trợ của nó. Về cơ bản, tôi có một bảng lưu trữ các yêu cầu đặt lại mật khẩu của người dùng (có chứa khóa đặt lại là loại byte[], hết hạn loại DateTime và khóa ngoài là User có chứa string Emailstring Name). Một số người dùng chưa đặt địa chỉ email, do đó, đối với một số PasswordRequest request, request.Emailnull.LINQ to Entities và chuỗi rỗng

Đây là vấn đề. Này hoạt động hoàn toàn tốt đẹp:

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; 

tôi nhận được số lượng dự kiến ​​của kết quả (khác không, vì có mục với null email).

Nhưng điều này luôn trả về một bộ sưu tập sản phẩm nào khi 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; 

Điều duy nhất mà tôi đã làm việc đúng cách (mà không logic thực hiện bất kỳ cảm giác) là:

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; 

Tôi hoàn toàn bối rối. Ý tưởng nào?

+0

Chính Gửi lĩnh vực trong bảng thực tế của bạn, là nó tuyên bố như là một cột NULL? – DoomerDGR8

+0

@HassanGulzar Thật vậy. – hydroiodic

+0

Bạn có thể đăng sql đã tạo không? – Marius

Trả lời

33

Về cơ bản đây là sự không khớp giữa SQL và C# khi nói đến việc xử lý các giá trị rỗng. Bạn không cần phải sử dụng hai truy vấn, nhưng bạn cần:

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

Đó là khó chịu, và có thể có một hàm helper để làm cho cuộc sống dễ dàng hơn, nhưng nó về cơ bản xuất phát từ việc xử lý vô SQL, nơi

where X = Y 

sẽ không phải phù hợp nếu cả X và Y đều rỗng. (Trong khi đó, biểu thức tương đương C# sẽ là đúng.)

Bạn cũng có thể cần thực hiện tương tự cho u, trừ khi điều đó không có giá trị trong cơ sở dữ liệu.

Một mẹo nhỏ bạn ít nhất có thể thử nếu bạn hài lòng với chuỗi rỗng và trống rỗng được xử lý theo cùng một cách là:

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

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

Tôi tin rằng sẽ thực hiện vô coalescing trên cả hai cột email và e, vì vậy bạn không bao giờ kết thúc so sánh null với bất kỳ thứ gì.

+1

Aha! Tôi mặc dù nó có thể đến đó, nhưng tôi không chắc chính xác điều gì đã gây ra điều đó. Cảm ơn bạn đã làm rõ! – hydroiodic

+0

+1 để hiểu nhanh và trả lời –

+0

Thật tuyệt vời! Các điều kiện nơi là một chút lỏng lẻo. Vì vậy, tôi đoán đặt cả ba giá trị có thể cho 'e' có ý nghĩa. – DoomerDGR8

3

Tôi đã tìm thấy một vài bài viết nêu chi tiết vấn đề tương tự. Thật không may, tôi đã không phải đối mặt với vấn đề này cho đến nay. Nó là rất thú vị mặc dù.

đây:

LINQ syntax where string value is not null or empty

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

Và từ MSDN: http://msdn.microsoft.com/en-us/library/bb882535.aspx

+0

Các liên kết hữu ích. Cảm ơn vì đăng! – hydroiodic

-1

Nếu bạn muốn lấy hàng từ DB khi yêu cầu [ 'e'] == null

phải là

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

lưu ý rằng == null và null khác nhau. xem ->MSDN Info

Do đó, ví dụ cuối cùng của bạn có giá trị vì bạn cần 2 cách để lấy dữ liệu từ DB. tức là một nếu email là null và một nếu email == Request [ 'e']

0

Nếu bạn thích sử dụng phương pháp (lambda) cú pháp như tôi, bạn có thể làm điều đó như thế này:

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; 
Các vấn đề liên quan