OrderBy в EF linq для сущностей не может справиться с тем совершенством, которое я ему бросаю. - PullRequest
0 голосов
/ 29 июля 2011

Я работаю над приложением, которое использует Entity Framework 3.5 и базу данных SQL.Приложение выполняет поиск графа объектов на основе некоторых критериев поиска, передаваемых из пользовательского интерфейса.Чтобы обработать функцию поиска, я использую конструктор запросов со следующим интерфейсом:

public interface IQueryBuilder
{
    IQueryable<SomeClass> BuildQuery(Criteria criteria);    
}

Объект критериев содержит несколько свойств, которые построитель запросов использует для фильтрации результатов поиска.Он также содержит свойство, определяющее порядок сортировки результатов, которое называется «OrderBy».Вот пример объекта критериев:

public class Criteria
{
    //some filter properties...

    public Expression<Func<SomeClass, object>> OrderBy { get; set; }
}

Итак, после того, как начальный запрос был построен, построитель запросов сортирует запрос с помощью:

var sortedQuery = query.OrderBy(criteria.OrderBy);

Это работает безотказно в модульных тестахи интеграционные тесты (где на самом деле хиты EF), когда я заказываю по строковому свойству (OrderBy = x => something.LastName).НО, когда я запускаю интеграционные тесты этого порядка с помощью нестрокового свойства (OrderBy = x => something.AgeInYears), EF выдает следующее исключение:

System.NotSupportedException: Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types.

В этом случае something.AgeInYearsint.EF не нравится тот факт, что я даю ему int вместо object.

ТАК, есть ли способ сделать то, что я пытаюсь сделать здесь?

Ответы [ 2 ]

3 голосов
/ 29 июля 2011

Я предполагаю, что вы не хотите (по уважительной причине) сделать свой класс критериев, например,

public class Criteria<T, U>
{
    //some filter properties...

    public Expression<Func<T, U>> OrderBy { get; set; }
}

, который должен работать ... так что вот пара альтернатив:

public class Criteria<T>
{
    //some filter properties...

    public Expression OrderBy { get; set; }


    public void CreateOrdering<U>(Expression<Func<T, U>> value)
    {
        OrderBy = value;
    }
}

, но так как OrderBy больше не является типизированным типом, вам нужно изменить код, который его применяет:

      var orderBy = Expression.Call(
            typeof(Queryable),
            "OrderBy",
            new Type[] { query.ElementType, query.ElementType },
            query.Expression,
            criteria.OrderBy);

      var sortedQuery = query.Provider.CreateQuery<T>(orderBy

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

вместо

var sortedQuery = query.OrderBy(criteria.OrderBy);

сделать что-то вроде (не проверял это, но должно быть в основном так) (ОБНОВЛЕНИЕ: у этого нет никаких предварительных предположений, что вы используетедженерики).

// grab the property expression out of your ordering statement
var expressionProperty = criteria.OrderBy.Body is UnaryExpression ? (MemberExpression)((UnaryExpression)criteria.OrderBy.Body).Operand : (MemberExpression)criteria.OrderBy.Body;

// recreate the lambda as Expression<Func<T,U>> where T is the queryable element type and U 
// is the actual type of the property, not an object

var orderBy = Expression.Lambda(expressionProperty, criteria.OrderBy.Parameters.Single());

// apply new lambda instead
var sortedQuery = query.OrderBy(orderBy);
0 голосов
/ 29 июля 2011

Проверьте методы в классе SqlFunctions , которые могут помочь в LINQ-безопасных преобразованиях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...