2012-10-17 12 views
5

Pytanie pierwotnie zadano pod http://entityframework.codeplex.com/discussions/399499#post928179.IQueryable nie implementuje IDbAsyncEnumerable

Dzień dobry! Proszę powiedzieć, czy to niewłaściwe miejsce, aby opublikować to pytanie.

Mam zapytanie co następuje:

IQueryable<Card> cardsQuery = 
    dataContext.Cards 
    .Where(predicate) 
    .OrderByDescending(kc => kc.SendDate) 
    .AsQueryable(); 

Potem spróbuj:

Task<Card[]> result = cardsQuery.ToArrayAsync();

I wtedy wyjątek wzrasta:

The source IQueryable doesn't implement IDbAsyncEnumerable<Models.Card>

Używam zmodyfikowana wersja "EF 5.x DbCotext generator".

Jak tego uniknąć?

UPDATE

Ważna uwaga jest taka, że ​​mam sposób wytwarzania IQuerayble<Card> następująco:

class Repository { 
    public IQueryable<Card> GetKudosCards(Func<Card, bool> predicate) { 
    IEnumerable<KudosCard> kudosCards = kudosCardsQuery.Where(predicate); 
    return kudosCards 
      .OrderByDescending(kc => kc.SendDate) 
      .AsQueryable(); 
    } 
} 
+0

Arthur (na http://entityframework.codeplex.com/discussions/399499#post928179) ma rację. Istnieje inna operacja między IQueryable <> i ToArrayAsync. Jest ODataQueryOptions.ApplyTo z pakietu OData. To materializuje IQueryable zgodnie z parametrami OData żądania HTTP. Mój kod jest zsynchronizowany, gdy ApplyTo jest zsynchronizowany, prawda? –

+0

Myślę, że otrzymujesz to, próbując napisać test. Jeśli nie chcesz zmieniać kodu produkcyjnego, wykonaj następujące czynności: http://msdn.microsoft.com/en-us/data/dn314429.aspx # async – Rikard

Odpowiedz

3

Problem jest następujący.

Mam metodę:

class Repository { 
    public IQueryable<Card> GetKudosCards(Func<Card, bool> predicate) { 
    IEnumerable<KudosCard> kudosCards = kudosCardsQuery.Where(predicate); 
    return kudosCards 
      .OrderByDescending(kc => kc.SendDate) 
      .AsQueryable(); 
    } 
} 

Problem polega na tym, że kudosCards ma typ IEnumerable<KudosCard>. To rzuca wyjątek. Jeśli zmienię typ predykatu na Expression<Func<Card, bool> predicate, wszystko działa dobrze.

6

Jaki jest sens wywoływania AsQueryable? Jeśli tworzysz zapytanie za pomocą metod rozszerzających, zaczynając od zbioru źródłowego IQueryable (np. DbSet, ObjectSet), zapytanie będzie również IQueryable.

Celem AsQueryable jest owijanie kolekcji IEnumerable za pomocą IQueryable proxy/adapter, który używa dostawcy Linq, który jest w stanie kompilować zapytania IQueryable w kwerendach Linq to Object. Może to być przydatne w scenariuszach, gdy chcesz używać zapytań o dane w pamięci.

Dlaczego wywołanie funkcji AsQueryable jest konieczne? Co jeśli po prostu go usuniesz?

Aktualizacja

Okey, teraz wydaje mi zrozumieć problem. Po szybkim spojrzeniu na ODataQueryOptions.ApplyTo zdałem sobie sprawę, że po prostu rozszerza ono podstawowe drzewo wyrażeń zapytania. Nadal możesz go użyć, aby uruchomić zapytanie w żądany sposób, jednak potrzebujesz trochę sztuczki, aby przekształcić zapytanie z powrotem na ogólne.

IQueryable<Card> cardsQuery = 
    dataContext.Cards 
    .Where(predicate) 
    .OrderByDescending(kc => kc.SendDate); 


IQueryable odataQuery = queryOptions.ApplyTo(cardsQuery); 

// The OData query option applier creates a non generic query, transform it back to generic 
cardsQuery = cardsQuery.Provider.CreateQuery<Card>(odataQuery.Expression); 

Task<Card[]> result = cardsQuery.ToArrayAsync(); 
+0

Wygląda na to, że masz rację. Mogę usunąć AsQueryable i jawnie rzucić OrderByDescending (...) do IQueryable . Mimo to nie stanowi to problemu. Problem polega na tym, że potrzebuję asynchronicznego żądania do bazy danych. Czy powinienem po prostu zawinąć ODataQueryOptions.ApplyTo na Task.Factory.StartNew? Nie sądzę, że to dobra decyzja, ponieważ żądanie db będzie blokowane. –

+0

Zaktualizowałem moją odpowiedź. – tamasf

+0

moje nagrody za trudną metodę! Masz rację mówiąc, że materializacja IQueryable występuje, gdy funkcja ToArray (Async) jest wywoływana, ale nie podczas queryOptions.ApplyTo. Jednak twoje podejście nie działa. Mam ten sam błąd: Źródło IQueryable nie implementuje IDbAsyncEnumerable . cardQuery ma typ {System.Linq.OrderedEnumerable'2 [Card, System.DateTime]}. –