2012-02-14 2 views
5

Я когда-то бил головой об этой проблеме. Есть несколько подобных случаев, но решения не применимы к моему делу.Динамический LINQ (для сущностей) Где с нулевым столбцом DateTime

У меня есть метод, который возвращает запрос фильтра в строчном формате. Метод имеет логику для различных типов данных, устанавливает правильные значения, имена столбцов и т.д.

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

Моя проблема заключается в том, что у меня есть Nullable DateTime в базе данных, и я String представление в стороне кода.

я попытался следующие запросы (String представления может быть неправильным в настоящее время):

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

Результат: '? DateTime' методов по типу не доступны

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

Результата: LINQ к Entities не распознает «) (System.String ToString» МЕТОДЫ, и этот метод не может быть переведен в выражение магазина.

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

Результат: '' или «(» ожидается

Любые идеи, как решить эту проблему?

Update (более исходный код добавляется о генерации запросов)

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

А вот класс фильтра и методы связанные с этим контекстом

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

ответ

2

LINQ to Entities не признает ToString() метод. Вам нужно будет оценить его, прежде чем вставлять результирующую строку в ваш запрос.

Для создания примеров в вашем вопросе вы можете справиться с этим, как это:

// "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\"", вероятно, не работает, потому что LINQ к EF не распознает тройной оператор (? :)

Изменить: Я понимаю из вашего комментария, что BirthDate - это столбец в вашей таблице, а не переменная.В этом случае вы можете получить все записи, преобразовывать их в список, а затем применить фильтр с помощью LINQ к объектам, как это (хотя вам придется изменить свой filterQuery соответственно):

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

Непроверенные: Это может можно использовать функцию CONVERT вашей базы данных:

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

BirthDate.ToString() - Что такое BirthDate в этом контексте? В моем случае это просто имя столбца, поэтому оно не существует в контексте кода. – Tx3

+0

Я вижу. Посмотрите мой обновленный ответ. –

+0

Спасибо, я попробую непроверенный подход также – Tx3

0

Моя проблема заключается в том, что у меня есть Nullable DateTime в базе данных и у меня есть представление строки в код на стороне.

Почему?

Измените кодовую сторону, проанализируйте представление строки и присвойте ей соответствующий объект в запросе LINQ.

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

BAD - Если вам нужно сделать строку manipulatzion, AWLWAYS использовать InvariantCulture. Этот код является хрупким и сломается в любой другой стране.

+0

Формат строки даты не имеет значения в этом вопросе. Да, это не правильно отформатировано в примере кода. Он может быть изменен на UTC integer. Я пытаюсь добиться того, что у меня будет один метод, который возвращает допустимые «критерии поиска» в строчном формате, чтобы он мог легко использоваться для всех типов дат. При необходимости я могу сделать исключение в nullable DateTime, но я бы предпочел избежать этого. – Tx3

+0

Вы правы, конечно, об InvariantCulture и о том, что код в настоящее время хрупок. – Tx3

+0

Не может быть сделано. Нет эффективного способа поиска, кроме «между» в датах времени в sql, и то, что может сделать LINQ, ограничено здесь. Ваш общий подход лучше учитывает особенности LINQ. – TomTom

0

В настоящее время я решаю это с помощью блока try/catch. Это добавляет некоторые накладные расходы и уродство, что я предпочел бы найти альтернативу, но это действительно работает очень солидно:

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

Примечание: Прием этих полей от входных переменных (rule.field и rule.data) опасно, и может открыть вам вплоть до (трудной) слепой SQL-инъекции. Первое значение (rule.field) может быть проверено на основе белого списка значений, чтобы предотвратить это.

Смежные вопросы