Je n'ai pas joué avec OData depuis un moment, mais je me souviens que c'était vraiment utile. J'ai donc opté pour une architecture .NetCore 3.1 EFCore + OData pour mon API. En vue de le rendre totalement générique etc. etc.

En faisant un petit test, je peux obtenir les résultats attendus depuis mon navigateur : par ex.

Https://localhost:44310/things?someidfield=44

Cool je récupère le JSON que j'attendais ! Mais c'est tellement lent, pourquoi ? En regardant le SQL (Profiler), je peux voir qu'il n'a pas de clause WHERE, il obtient tout de la base de données et le filtre en mémoire, sur un demi-million d'enregistrements ?

Qu'est-ce que j'oublie ici? J'ai essayé plusieurs façons d'écrire la méthode GET. En commençant par ne transmettre aucune option de requête (ce qui a fonctionné ! mais le même résultat en dessous), puis ci-dessous où j'applique explicitement les options à l'entité EFCore.

        [HttpGet]
        [EnableQuery]
        public async Task<IEnumerable<thing>> GetThingsAsync(ODataQueryOptions<thing> queryOptions)
        {
           return await queryOptions.ApplyTo(DB.thing).Cast<thing>().ToListAsync();
        }
0
Mr AH 4 nov. 2020 à 20:19

1 réponse

Meilleure réponse

Le jeu de résultats est chargé en mémoire car vous appelez ToListAsync() et renvoyez un IEnumerable.

Si votre méthode GetThingsAsync renvoie un IQueryable<T> (au lieu de IEnumerable<T>), alors la requête sera appliquée à la base de données et seules les données filtrées seront récupérées.

Si DB.thing est un EFCore DbSet (qui implémente IQueryable<T>), alors vous pouvez simplifier votre méthode comme

[HttpGet]
[EnableQuery]
public Task GetThingsAsync()
{
  return DB.thing;
}

De plus, comme certains dans le commentaire déjà mentionné, la syntaxe correcte pour le filtrage dans votre cas serait ?$filter=someidfield eq 44

0
habbes 5 nov. 2020 à 09:23