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ément | Valeur |
|---|---|
| Suffixe de requête de données | $qd |
| En-tête de détection | isQuery |
| Constante du suffixe | IDataQueryRequest.QueryIdentifier |
| Constante d'en-tête | IDataQueryRequest.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.
[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,
});
}
}
LgControllerBaseLes 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.
@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>
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 client | Effet serveur |
|---|---|
Filters | Applique les filtres de colonnes. |
Sorts | Applique l'ordre de tri. |
CurrentPage / PageSize | Retourne uniquement la page demandée. |
TotalCount | Calcule le nombre total de lignes si demandé. |
DistinctProperty | Retourne les valeurs distinctes d'une propriété. |
Calculations | Retourne les calculs demandés. |
Export | Retourne un fichier avec le fournisseur d'export demandé. |
ExportProviders | Expose les fournisseurs d'export déclarés sur l'action. |
Points d'attention
| Point | Règle |
|---|---|
| Type retourné | Préférer IQueryable<T> pour laisser EF Core composer la requête SQL. |
| Projection | Projeter 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. |
| Erreurs | Pour les actions avec logique métier, utiliser try / catch et Problem(ex) via LgControllerBase. |
| Export | Les exports sont gérés dans le filtre lorsque Export est présent dans la requête. |
Exemple avec gestion d'erreur
[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);
}
}