Linq Entity Framework - могу ли я использовать рекурсивный метод? - PullRequest
0 голосов
/ 12 июля 2010

Исходя из отличного ответа на мой предыдущий вопрос:

Метод универсального фильтра Linq Entity Framework

Сейчас я пытаюсь понять, как я могу применить что-то вроде рекурсии к своему решению.

Подведем итог, вместо нескольких похожих объявлений этого метода:

protected IQueryable<Database.Product> GetActiveProducts( ObjectSet<Database.Product> products ) {

    var allowedStates = new string[] { "Active" , "Pending" };

    return (
        from product in products
        where allowedStates.Contains( product.State )
            && product.Hidden == "No"
        select product
    );

}

Теперь у меня есть одна реализация, которая принимает интерфейсный тип (IHideable) для работы:

protected IQueryable<TEntity> GetActiveEntities<TEntity>( ObjectSet<TEntity> entities ) where TEntity : class , Database.IHideable {

    var allowedStates = new string[] { "Active" , "Pending" };

    return (
        from entity in entities
        where allowedStates.Contains( entity.State )
            && entity.Hidden == "No"
        select entity
    );

}

Это работает хорошо, и решение чисто и понятно (большое спасибо https://stackoverflow.com/users/263693/stephen-cleary).

Сейчас я пытаюсь применить аналогичный (или такой же?) Метод к любым объектам EntityCollections, связанным с объектом EntityObject, которые также реализуют IHideable.

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

var products = GetActiveEntities( Entities.Products );

return (

    from product in products

    let latestOrder = product.Orders.FirstOrDefault( 
        candidateOrder => (
            candidateOrder.Date == product.Orders.Max( maxOrder => maxOrder.Date )
        )       
    )

    select new Product() {

        Id = product.Id ,
        Name = product.Name,
        LatestOrder = new Order() {

            Id = latestOrder.Id ,
            Amount = latestOrder.Amount,
            Date = latestOrder.Date

        }

    }

);

В этом примере я хотел бы, чтобы Order EntityCollection также фильтровал по GetActiveEntities (), чтобы последний возвращаемый заказ никогда не мог быть "скрытым".

Возможно ли, чтобы все EntityCollections, реализующие IHideable, были отфильтрованы - может быть, применяя некоторое отражение / рекурсию внутри GetActiveEntities () и вызывая себя? Я говорю рекурсия, потому что наилучшим решением будет многоуровневое углубление в графе сущностей.

Этот материал растягивает мой мозг!

ОБНОВЛЕНИЕ # 1 (мои комментарии перенесены сюда)

Спасибо, Стив.

Принятие метода IQuerable, как предлагается, выдает эту ошибку:

'System.Data.Objects.DataClasses.EntityCollection<Database.Order>' does not contain a definition for 'GetActiveEntities' and no extension method 'GetActiveEntities' accepting a first argument of type 'System.Data.Objects.DataClasses.EntityCollection<Database.Order>' could be found (are you missing a using directive or an assembly reference?)

Я предполагаю, что это потому, что EntityCollection не реализует IQueryable.

Мне удалось продвинуться дальше, создав второй метод расширения, который явно принимал EntityCollection и возвращал IEnumerable. Это скомпилировано, но во время выполнения выдало эту ошибку:

LINQ to Entities does not recognize the method 'System.Collections.Generic.IEnumerable`1[Database.Order] GetActiveEntities[Order](System.Data.Objects.DataClasses.EntityCollection`1[Database.Order])' method, and this method cannot be translated into a store expression.

Я также пытался вызвать AsQueryable () для EntityCollection и вернуть IQueryable, но та же ошибка вернулась.

1 Ответ

2 голосов
/ 12 июля 2010

Отредактировано для использования ObjectSet вместо EntityCollection

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

public static IQueryable<TEntity> WhereActive<TEntity>(
    this IQueryable<TEntity> entities)
    where TEntity : class , Database.IHideable
{
    var allowedStates = new string[] { "Active", "Pending" };

    return (
        from entity in entities
        where allowedStates.Contains(entity.State)
            && entity.Hidden == "No"
        select entity
    );
}  

Это может быть использовано как таковое:

var products = Entities.Products.WhereActive();

return (

    from product in products

    let latestOrder = (
        from order in Entities.Orders.WhereActive()
        where order.ProductId == product.Id
        orderby candidateOrder.Date descending
        select order).FirstOrDefault()

    select new Product()
    {
        Id = product.Id,
        Name = product.Name,
        LatestOrder = new Order()
        {
            Id = latestOrder.Id,
            Amount = latestOrder.Amount,
            Date = latestOrder.Date
        }
    }
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...