EF6 IQueryable dynamic linq Где (предикат, значения) с DbFunctions.TruncateTime

В моем упрощенном примере у меня есть объект со следующими свойствами:

  • Имя (строка)
  • BirthDateTimeStamp (дата/время)

Мне нужно уметь строить динамические запросы следующим образом

var predicate = "Name = @0";
var values = new object[]{"Ed"};
myIQueryableDataSource.Where(predicate, values)

Эта работа хорошая. Теперь я хочу сравнить дату и время

var predicate = "BirthDateTimeStamp >= @0";
var values = new object[]{someDateTime};

Это тоже хорошо работает. Но то, что я на самом деле хочу сделать при сравнении даты и времени, и эта проблема лучше проявляется при выполнении равных, сравнивается только по дате.

var predicate = "BirthDateTimeStamp.Date >= @0";

Это невозможно, так как свойство Date не распознается EF для SQL-сервера.

var predicate = "System.Data.Entity.DbFunctions.TruncateTime(BirthDateTimeStamp) >= @0";

Это также не работает, так как я могу получить доступ к своим свойствам объекта только в предикате.

Как я могу решить это таким образом, чтобы предикат оставался в строковом формате. Этот код является лишь частью большого существующего синтаксического анализатора для моих запросов и может быть полностью переписан.


person JMan    schedule 13.01.2016    source источник


Ответы (2)


См. https://stackoverflow.com/a/26451213/525788.

System.Linq.Dynamic анализирует выражение, указанное вами как C#, но не распознает класс DbFunctions. Однако вы можете исправить DbFunctions как предопределенный тип:

var type = typeof( DynamicQueryable ).Assembly.GetType( "System.Linq.Dynamic.ExpressionParser" );

FieldInfo field = type.GetField( "predefinedTypes", BindingFlags.Static | BindingFlags.NonPublic );

Type[] predefinedTypes = (Type[])field.GetValue( null );

Array.Resize( ref predefinedTypes, predefinedTypes.Length + 1 );
predefinedTypes[ predefinedTypes.Length - 1 ] = typeof( DbFunctions );

field.SetValue( null, predefinedTypes );

Затем вы можете использовать

var predicate = "DbFunctions.TruncateTime(BirthDateTimeStamp) >= @0";
person RockResolve    schedule 15.09.2016

Ответ, данный @RockResolve, действительно сработал, но это своего рода взлом. Linq Dynamics предоставляет функциональные возможности для добавления пользовательских функций.

public class CustomTypeProvider: IDynamicLinkCustomTypeProvider
{
    public HashSet<Type> GetCustomTypes()
    {
      HashSet<Type> types = new HashSet<Type>();
      // adding custom types
      types.Add(typeof(DbFunctions)); 
      return types;
    }
}

// use below line to add this to linq
System.Linq.Dynamics.GlobalConfig.CustomTypeProvider = new CustomTypeProvier();
person SATYENDRA SINGH PANWAR    schedule 16.05.2018