web-dev-qa-db-fra.com

Quel est le but de AsQueryable ()?

Le but de AsQueryable() est-il juste pour que vous puissiez transmettre un IEnumerable à des méthodes qui pourraient s’attendre à IQueryable, ou existe-t-il une raison utile de représenter IEnumerable comme IQueryable? Par exemple, est-ce censé être pour des cas comme celui-ci:

IEnumerable<Order> orders = orderRepo.GetAll();

// I don't want to create another method that works on IEnumerable,
// so I convert it here.
CountOrders(orders.AsQueryable());

public static int CountOrders(IQueryable<Order> ordersQuery)
{
    return ordersQuery.Count();
}

Ou est-ce que cela fait réellement quelque chose de différent:

IEnumerable<Order> orders = orderRepo.GetAll();
IQueryable<Order> ordersQuery = orders.AsQueryable();

IEnumerable<Order> filteredOrders = orders.Where(o => o.CustomerId == 3);
IQueryable<Order> filteredOrdersQuery = ordersQuery.Where(o => o.CustomerId == 3);

// Are these executed in a different way?
int result1 = filteredOrders.Count();
int result2 = filteredOrdersQuery.Count();

Est-ce que les versions IQueryable de ces méthodes d'extension ne font que construire une expression qui finit par faire la même chose une fois qu'elle est exécutée? Ma question principale est: quel est le cas d'utilisation réel de AsQueryable?

90
Ocelot20

Il y a quelques utilisations principales.

  1. Comme mentionné dans d'autres réponses, vous pouvez l'utiliser pour simuler une source de données interrogeable à l'aide d'une source de données en mémoire afin de pouvoir tester plus facilement des méthodes qui seront éventuellement utilisées sur un IQueryable non-énumérable.

  2. Vous pouvez écrire des méthodes auxiliaires de manipulation de collections pouvant s'appliquer à des séquences en mémoire ou à des sources de données externes. Si vous écrivez vos méthodes d'aide pour utiliser entièrement IQueryable, vous pouvez simplement utiliser AsQueryable sur tous les enumerables pour les utiliser. Cela vous permet d'éviter d'écrire deux versions distinctes de méthodes d'assistance très généralisées.

  3. Cela vous permet de changer le type de temps de compilation d'un objet interrogeable afin qu'il soit un IQueryable, plutôt qu'un type plus dérivé. En effet; vous l'utiliseriez sur un IQueryable au même moment que vous utiliseriez AsEnumerable sur un IEnumerable. Vous pouvez avoir un objet qui implémente IQueryable mais qui a aussi une méthode instance Select. Si tel était le cas et que vous souhaitiez utiliser la méthode LINQ Select, vous devrez modifier le type de temps de compilation de l'objet pour IQueryable. Vous pouvez simplement le lancer, mais en utilisant une méthode AsQueryable, vous pouvez tirer parti de l'inférence de type. Ceci est simplement plus pratique si la liste des arguments génériques est complexe et qu’elle est en fait nécessaire si l’un des arguments génériques est de type anonyme.

56
Servy

Le cas le plus valable que j'ai pour AsQueryable est le test unitaire. Disons que j'ai l'exemple suivant quelque peu artificiel

public interface IWidgetRepository
{
   IQueryable<Widget> Retrieve();
} 

public class WidgetController
{
   public IWidgetRepository WidgetRepository {get; set;}


   public IQueryable<Widget> Get()
   {
      return WidgetRepository.Retrieve();
   }
}

et je veux écrire un test unitaire pour m'assurer que le contrôleur retransmet les résultats renvoyés du référentiel. Cela ressemblerait à ceci:

[TestMethod]
public void VerifyRepositoryOutputIsReturned()
{    
    var widget1 = new Widget();
    var widget2 = new Widget();
    var listOfWidgets = new List<Widget>() {widget1, widget2};
    var widgetRepository = new Mock<IWidgetRepository>();
    widgetRepository.Setup(r => r.Retrieve())
      .Returns(listOfWidgets.AsQueryable());
    var controller = new WidgetController();
    controller.WidgetRepository = widgetRepository.Object;

    var results = controller.Get();

    Assert.AreEqual(2, results.Count());
    Assert.IsTrue(results.Contains(widget1));
    Assert.IsTrue(results.Contains(widget2));
}

où vraiment, toute la méthode AsQueryable () me permet de satisfaire le compilateur lors de la configuration d'une maquette.

Je serais intéressé par où ceci est utilisé dans le code d'application cependant.

10
chris

Comme sanjuro l'a noté, le but de AsQueryable () est expliqué dans tilisation de AsQueryable avec Linq vers des objets et Linq vers SQL . L'article dit notamment:

Cela offre d’excellents avantages dans les scénarios Word réels dans lesquels certaines méthodes sur une entité renvoient une liste IQueryable de T et certaines méthodes renvoient une liste. Mais ensuite, vous devez appliquer un filtre de règle métier sur toute la collection, que celle-ci soit renvoyée au format IQueryable ou T ou IEnumerable ou T. Du point de vue des performances, vous souhaitez vraiment exploiter l'exécution du filtre métier sur la base de données si la collection implémente IQueryable sinon, retombez pour appliquer le filtre métier en mémoire en utilisant Linq pour implémenter en objet les délégués.

8
Scott

Le but de AsQueryable () est expliqué en détail dans cet article tilisation de AsQueryable avec Linq to Objects et Linq to SQL

De la section Remarques de la méthode MSDN Queryable.AsQueryable:

Si le type de source implémente IQueryable, AsQueryable (IEnumerable) le renvoie directement. Sinon, il retourne un IQueryable qui exécute des requêtes en appelant les méthodes d'opérateur de requête équivalentes dans Enumerable au lieu de celles dans Queryable.

C’est exactement ce qui est mentionné et utilisé dans l’article ci-dessus. Dans votre exemple, cela dépend de ce que orderRepo.GetAll renvoie, IEnumerable ou IQueryable (Linq à Sql). S'il renvoie IQueryable, la méthode Count () sera exécutée sur une base de données, sinon elle sera exécutée en mémoire. Regardez attentivement l'exemple dans l'article référencé.

3
sanjuro

Interface IQueryable citant la documentation:

L'interface IQueryable est destinée à être implémentée par les fournisseurs de requêtes.

Donc, pour quelqu'un qui a l'intention de rendre sa structure de données interrogeable dans .NET, cette structure de données qui n'est pas nécessaire peut être énumérée ou avoir un énumérateur valide.

IEnumerator est une interface pour l'itération et le traitement flux de données.

2
Tigran