2012-02-14 16 views
5

ile birlikte Başımdan bu sorunla başa çıkıyorum. Bazı benzer durumlar var, ancak çözümler benim durumumda geçerli değildi.Dinamik LINQ (varlıklar için) Neredebildiğiniz DateTime sütunu

Dize biçiminde filtre sorgusu döndüren bir yöntem var. yöntem farklı veri türleri için mantığı var, doğru değerleri, sütun adları vb

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

Sorunum veritabanında Nullable DateTime var ve kod tarafında String temsil hakkına sahip olmasıdır ayarlar.

denedim aşağıdaki sorguları (String temsil yanlış şu anda olabilir):

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

Sonuç: '? DateTime' Yöntemleri türüne Varlıkları için LINQ yöntemi 'System.string .ToString()' yöntemi tanımaz, ve bu yöntem, bir mağaza ifade tercüme edilemez:

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

Sonuç erişilemez.

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

Sonuç: '' ya da '('

Güncelleme (daha kaynak kodu sorgu nesil) burada

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); 
} 

Ve yaklaşık eklendi? Bir sınıf Filtre sorunu çözmek ve yöntemlerdir nasıl Herhangi fikirler beklenen bu bağlamla ilgili

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; 
} 

cevap

2

LINQ to Varlıklartanımamıştırmetodu. Sonuçtaki dizeyi sorgunuza eklemeden önce değerlendirmelisiniz.

sorunuzu örneklerini oluşturmak için böyle idare olabilir: EF LINQ üçlü operatörü tanımadığından

muhtemelen
// "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\"" çalışmıyor (? :)

Düzenleme: Yorumunuzdan BirthDate tablonuzdaki bir değişken değil, bir değişken olduğunu anlıyorum.Bu durumda, tüm girdileri alabilir bunları bir listeye dönüştürmek ve (buna göre filterQuery değiştirmek zorunda kalacak rağmen) sonra böyle LINQ nesnelere kullanarak filtre uygulamak:

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

Untested: Bu olabilir veritabanınızın CONVERT fonksiyonunu kullanmak mümkün:

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

BirthDate.ToString() - Bu bağlamda Doğum tarihi nedir? Benim durumumda sadece bir sütun adı, bu yüzden kod bağlamında mevcut değil. – Tx3

+0

Anladım. Güncellenmiş yanıtıma bir göz atın. –

+0

Teşekkürler, ayrıca test edilmemiş yaklaşımı da deneyeceğim – Tx3

0

sorunum veritabanında null DateTime var ve kod tarafı string temsil hakkına sahip olmasıdır.

Neden?

Kod tarafını değiştirin, dize gösterimini ayrıştırın ve LINQ sorgusunda uygun nesneyi verin.

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

KÖTÜ "00 \" - Eğer dize manipulatzion yapmak zorunda EĞER AWLWAYS InvariantCulture kullanın. Bu kod kırılgandır ve başka herhangi bir ülkede kırılacaktır.

+0

Tarih dizesi biçimi bu soruyla alakalı değil. Evet, örnek kodda düzgün şekilde biçimlendirilmemiş. UTC tamsayı olarak değiştirilebilir. Yapmaya çalıştığım şey, dize biçiminde geçerli "arama ölçütleri" döndüren bir yönteme sahip olmaktır, böylece her tür tarih türü için kolayca kullanılabilir. Gerekirse, geçersiz DateTime konusunda bir istisna yapabilirim, ancak bundan kaçınmayı tercih ederim. – Tx3

+0

Elbette InvariantCulture ve kodun şu anda kırılgan olmasıyla ilgili haklısınız. – Tx3

+0

Yapılamaz. Bundan dolayı, sql'de tarih aralarında "ara" dışında arama yapmak için verimli bir yol yoktur ve LINQ'un yapabileceği şey burada sınırlıdır. Genel yaklaşımınız daha iyi LINQ prticularities dikkate alır. – TomTom

0

Şu anda bunu bir try/catch bloğu ile çözüyorum. Ben doğrusu için bir alternatif görmeyeceği yükü ve çirkinlik ekler, ama çok sağlam çalışır:

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); 
} 

Not: girdi değişkenleri (rule.field ve rule.data) gelenler alanları kabulü tehlikelidir ve sizi açılabilir (zor) kör bir SQL Enjeksiyonuna kadar. Bunu önlemek için ilk değer (rule.field) bir beyaz liste değerine karşı kontrol edilebilir.

İlgili konular