2010-07-12 4 views
0

Вслед за отличный ответ на мой предыдущий вопрос:Linq Entity Framework - могу ли я использовать рекурсивный метод?

Linq Entity Framework generic filter method

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

Напомним, что вместо нескольких подобных заявлений этого метода:

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 

     } 

    } 

); 

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

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

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

UPDATE # 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, но та же ошибка вернулась.

ответ

2

Edited использовать 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 
     } 
    } 
); 
+0

Спасибо за ответ Стивен. Я на самом деле реорганизовал метод в метод расширения ранее сегодня, но не хотел увязывать этот пример, поэтому использовал вызов метода. Приятно знать, что это был правильный ход - большая часть функциональных возможностей языка C# для меня нова. – FantasticJamieBurns

+0

Спасибо Стив, я переместил свои комментарии в область вопросов, чтобы упростить чтение ... – FantasticJamieBurns

+0

Вы правы: 'EntityCollection' не реализует' IQueryable'. Я обновил свой ответ, чтобы использовать 'Entities.Orders', а не' product.Orders', который должен работать. (Я также изменил расчет 'lastOrder', чтобы использовать' orderby'). –

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