Aller au contenu principal

Attribut Queryable et requêtage OData

QueryableAttribute est un filtre d'action serveur. Il lit les requêtes de données émises par les composants Lagoon, puis applique au résultat les filtres, tris, pages, calculs, requêtes distinctes et exports demandés.

LgGridView utilise ce mécanisme quand elle charge des données distantes via ControllerUri. Voir aussi la page LgGridView.

Principe​

Le client poste une requête vers l'URI du contrôleur suffixée par $qd. Le middleware serveur détecte ce suffixe, route la requête vers l'action GET réelle et ajoute l'en-tête isQuery.

ÉlémentValeur
Suffixe de requête de données$qd
En-tête de détectionisQuery
Constante du suffixeIDataQueryRequest.QueryIdentifier
Constante d'en-têteIDataQueryRequest.HeaderQueryIdentifier

QueryableAttribute charge alors le corps de requête, exécute l'action, récupère la valeur retournée et applique la transformation via ResponseFactory<T>.

Contrat côté contrôleur​

Appliquez [Queryable] sur une action qui retourne une source requêtable. L'action peut recevoir un QueryArg<T> pour récupérer l'argument métier envoyé par la grille.

FirmsController.cs
[Authorize]
[Route("api/[controller]")]
public class FirmsController : LgControllerBase
{
private readonly ApplicationDbContext _db;

public FirmsController(ApplicationDbContext db)
{
_db = db;
}

[Queryable]
[HttpGet("GetFirmsByCountry")]
public IQueryable<VmCountryFirm> Get(QueryArg<int?> data)
{
// Retourne une requête EF Core : Lagoon appliquera filtres, tris et pagination après l'action.
return _db.Firms.Where(c => c.CountryId == data.Value).Select(x => new VmCountryFirm
{
Id = x.Id,
FirmName = x.Name,
});
}
}
astuce
LgControllerBase

Les contrôleurs API Lagoon héritent de LgControllerBase afin de bénéficier de la gestion d'erreurs standardisée avec Problem(ex) et des helpers serveur du framework.

Requêtage depuis LgGridView​

Côté client, LgGridView configure le chargement distant avec ControllerUri. Les filtres, tris, pagination et exports configurés par l'utilisateur sont envoyés automatiquement.

FirmsPage.razor
@inherits LgPage

<LgGridView TItem="VmCountryFirm"
StateId="firms-by-country"
ControllerUri="api/Firms/GetFirmsByCountry"
ControllerQueryArg="_countryId"
Title="#FirmsTitle">
<Columns Context="firm">
<LgGridTextColumn @bind-Value="firm.FirmName" Title="#FirmName" />
</Columns>
</LgGridView>
FirmsPage.razor.cs
public partial class FirmsPage : LgPage
{
// Argument métier transmis au contrôleur dans QueryArg<int?>.
private int? _countryId = 1;
}

Ce que l'attribut applique​

Demande clientEffet serveur
FiltersApplique les filtres de colonnes.
SortsApplique l'ordre de tri.
CurrentPage / PageSizeRetourne uniquement la page demandée.
TotalCountCalcule le nombre total de lignes si demandé.
DistinctPropertyRetourne les valeurs distinctes d'une propriété.
CalculationsRetourne les calculs demandés.
ExportRetourne un fichier avec le fournisseur d'export demandé.
ExportProvidersExpose les fournisseurs d'export déclarés sur l'action.

Points d'attention​

PointRègle
Type retournéPréférer IQueryable<T> pour laisser EF Core composer la requête SQL.
ProjectionProjeter vers un ViewModel avant le retour pour ne pas exposer l'entité EF Core complète.
Exécution anticipéeÉviter ToList() avant le retour : filtres et tris seraient appliqués en mémoire.
ErreursPour les actions avec logique métier, utiliser try / catch et Problem(ex) via LgControllerBase.
ExportLes exports sont gérés dans le filtre lorsque Export est présent dans la requête.

Exemple avec gestion d'erreur​

FirmsController.cs
[Queryable]
[HttpGet("GetFirmsByCountry")]
public IActionResult GetFirmsByCountry(QueryArg<int?> data)
{
try
{
// Conserve IQueryable jusqu'au retour pour permettre le requêtage serveur.
IQueryable<VmCountryFirm> firms = _db.Firms.Where(c => c.CountryId == data.Value).Select(x => new VmCountryFirm
{
Id = x.Id,
FirmName = x.Name,
});
return Ok(firms);
}
catch (Exception ex)
{
return Problem(ex);
}
}