2012-02-14 25 views
5

Tôi đã đập đầu vào vấn đề này đôi khi. Có một số trường hợp tương tự, nhưng các giải pháp không áp dụng cho trường hợp của tôi.LINQ động (đối với thực thể) Ở đâu có cột DateTime không thể sử dụng

Tôi có phương thức trả về truy vấn bộ lọc ở định dạng chuỗi. Phương pháp này có logic với nhiều loại dữ liệu khác nhau, đặt giá trị đúng, tên cột, vv

string filterQuery = GetFilterQuery(params); 
rows = rows.Where(filterQuery); 

Vấn đề của tôi là tôi có Nullable DateTime trong cơ sở dữ liệu và tôi có String đại diện ở phía mã.

Tôi đã cố gắng truy vấn sau đây (String đại diện có thể là sai hiện tại):

"BirthDate.ToString() = \"16.2.2012 22:00:00\"" 

quả: '? DateTime' Phương pháp theo loại không thể truy cập

"BirthDate.Value.ToString() = \"16.2.2012 22:00:00\"" 

quả: LINQ to Entities không nhận ra phương pháp 'System.String ToString()' phương pháp, và phương pháp này không thể được dịch sang một biểu hiện cửa hàng.

"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\"" 

quả: '' hay '(' dự kiến ​​

Bất kỳ ý tưởng làm thế nào để giải quyết vấn đề?

Cập nhật (mã nguồn hơn thêm về thế hệ truy vấn)

var filterQueries = query.GridFilteringOptions.filters 
    // remove filters that doesn't have all the required information 
    .Where(o => o.name != string.Empty && o.value != string.Empty && !string.IsNullOrEmpty(o.type)) 
    // remove filters that are filtering other tables than current 
    .Where(o => o.table == tableName) 
    .Select(filter => filter.ResolveQuery()).ToList(); 

if (filterQuery.Any()) 
{ 
    var filterQuery = string.Join(" And ", filterQueries); 
    rows = rows.Where(filterQuery); 
} 

Và đây là một bộ lọc lớp và phương pháp liên quan đến ngữ cảnh này

public string ResolveQuery() 
{ 
    if (type == "Int64") 
    { 
     return ResolveInteger(); 
    } 
    else if(type == "String") 
    { 
     return ResolveString(); 
    } 
    else if(type == "DateTime") 
    { 
     return ResolveDateTime(); 
    } 
    else 
    { 
     return string.Empty; 
    } 
} 

private string ResolveDateTime() 
{ 
    DateTime result = new DateTime(); 
    if (DateTime.TryParse(this.value, out result)) 
    { 
     return string.Format("{0}.ToString() = \"{1}\"", this.name, result.ToUniversalTime()); 
    } 
    return string.Empty; 
} 

private string ResolveString() 
{ 
    switch (@operator) 
    { 
     default: 
      return string.Format(@"{0}.StartsWith(""{1}"")", this.name, this.value); 
    }    
} 

private string ResolveInteger() 
{ 
    string tmp = this.name; 
    switch (@operator) 
    { 
     case -1: 
      return string.Empty; 
     case 0: 
      tmp += "<"; 
      break; 
     case 1: 
      tmp += "="; 
      break; 
     case 2: 
      tmp += ">"; 
      break; 
     default: 
      return string.Empty; 
    } 
    tmp += value; 
    return tmp; 
} 

Trả lời

2

LINQ to Entities không nhận ra ToString(). Bạn sẽ phải đánh giá nó trước khi chèn chuỗi kết quả vào truy vấn của bạn.

Để tạo các ví dụ trong câu hỏi của bạn, bạn có thể xử lý nó như thế này:

// "BirthDate.ToString() = \"16.2.2012 22:00:00\"" 
string birthdate = BirthDate.ToString(); 
string query = String.Format("{0} = \"16.2.2012 22:00:00\"", birthdate); 

// "BirthDate.Value.ToString() = \"16.2.2012 22:00:00\"" 
string birthdate = BirthDate.Value.ToString(); 
string query = String.Format("{0} = \"16.2.2012 22:00:00\"", birthdate); 

"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\"" lẽ không hoạt động vì LINQ to EF không công nhận các nhà điều hành ternary (? :)

Edit: Tôi hiểu từ bình luận của bạn rằng BirthDate là một cột trong bảng của bạn, không phải là một biến.Trong trường hợp này bạn có thể lấy tất cả các mục, chuyển đổi chúng vào một danh sách và sau đó áp dụng bộ lọc sử dụng LINQ to Objects như thế này (mặc dù bạn sẽ phải thay đổi filterQuery bạn cho phù hợp):

string filterQuery = GetFilterQuery(params); 
var filteredRows = rows.ToList().Where(filterQuery); 

chưa được kiểm tra: Nó có thể có thể sử dụng chức năng của cơ sở dữ liệu của bạn CONVERT:

string query = "CONVERT(varchar(20), BirthDate) = \"16.2.2012 22:00:00\""; 
+0

BirthDate.ToString() - Ngày sinh là gì trong ngữ cảnh này? Trong trường hợp của tôi chỉ là một tên cột, vì vậy nó không tồn tại trong ngữ cảnh mã. – Tx3

+0

Tôi hiểu. Hãy xem câu trả lời cập nhật của tôi. –

+0

Cảm ơn, tôi sẽ thử cách tiếp cận chưa được kiểm tra cũng – Tx3

0

vấn đề của tôi là tôi có Nullable DateTime trong cơ sở dữ liệu và tôi có chuỗi đại diện trong phía mã.

Tại sao?

Thay đổi mặt mã, phân tích cú pháp biểu diễn chuỗi và đặt cho đối tượng thích hợp trong truy vấn LINQ.

"BirthDate.ToString() = \" 2012/02/16 22: 00: 00 \ ""

BAD - NẾU bạn phải làm chuỗi manipulatzion, AWLWAYS sử dụng InvariantCulture. Mã này rất mỏng manh và sẽ phá vỡ ở bất kỳ quốc gia nào khác.

+0

Định dạng chuỗi ngày không có liên quan trong câu hỏi này. Có, nó không được định dạng đúng trong mã ví dụ. Nó có thể được thay đổi thành số nguyên UTC. Những gì tôi cố gắng thực hiện là tôi sẽ có một phương thức trả về "tiêu chí tìm kiếm" hợp lệ ở định dạng chuỗi, để nó có thể được sử dụng dễ dàng cho tất cả các loại ngày tháng. Nếu cần thiết tôi có thể làm cho một ngoại lệ trên DateTime nullable, nhưng tôi thà tránh nó. – Tx3

+0

Bạn đang phải tất nhiên về InvariantCulture và về mã hiện đang mong manh. – Tx3

+0

Không thể thực hiện được. Đây không phải là cách hiệu quả để tìm kiếm ngoại trừ "giữa" trong thời gian ngày trên sql, và những gì LINQ có thể làm được giới hạn ở đây. Cách tiếp cận chung của bạn tốt hơn cần xem xét kỹ lưỡng LINQ. – TomTom

0

Tôi hiện đang giải quyết vấn đề này với khối thử/nắm bắt. Có thêm một số phí và xấu xa mà tôi thà tìm một sự thay thế cho, nhưng nó làm việc rất kiên cố:

try 
{ 
    // for strings and other non-nullables 
    records = records.Where(rule.field + ".ToString().Contains(@0)", rule.data); 
} 
catch (System.Linq.Dynamic.ParseException) 
{ 
    // null types 
    records = records.Where(rule.field + ".Value.ToString().Contains(@0)", rule.data); 
} 

Lưu ý: Chấp nhận những lĩnh vực từ các biến đầu vào (các rule.fieldrule.data) là nguy hiểm, và có thể mở bạn đến một SQL Injection mù (khó). Giá trị đầu tiên (rule.field) có thể được kiểm tra đối với danh sách trắng các giá trị, để ngăn chặn điều này.

Các vấn đề liên quan