<FetchXmlBuilder> modifie une requête FetchXML sans que personne n’écrive FetchXML. Il couvre les parties du langage que les gens utilisent réellement — la table, les colonnes qu’il renvoie, la façon dont les lignes sont triées, ainsi qu’un arbre de filtres de conditions et de groupes imbriqués — et il rejoint les tables associées, les agrège, et exécute ce qu’il a construit.
Le vrai composant par rapport aux métadonnées de cet environnement. Choisissez une table, ajoutez une colonne ou une condition, rejoignez une table associée, et regardez le panneau FetchXML suivre — puis appuyez sur Exécuter pour voir ce que correspond la requête.
Ce n’est pas la même chose que FetchXMLBuilder
Cette page concerne le composant.
FetchXMLBuilderest la classe C# qui compose le même XML en code, pour un appelant côté serveur qui construit une requête manuellement. Ils produisent la même chose et aucun n’a besoin de l’autre.
Chaque tableau, colonne et relation est choisie à partir de ce que l’environnement possède réellement. C’est délibéré : un nom logique tapé à la main produit FetchXML qui analyse parfaitement puis échoue sur Dataverse, ce qui est le pire type d’erreur à donner à quelqu’un. Le usePowerPortalsProFetchXmlMetadata crochet connecte le constructeur aux points de terminaison de métadonnées mises en cache du framework, de sorte que les sélectionneurs partagent ce que les grilles sur la même page ont déjà récupéré.
// La page de tout le câblage sur un portail.
import { FetchXmlBuilder, usePowerPortalsProFetchXmlMetadata } from '@powerportalspro/react-fluent';
export function QueryEditor() {
const metadata = usePowerPortalsProFetchXmlMetadata();
const [fetchXml, setFetchXml] = useState('');
return <FetchXmlBuilder value={fetchXml} onChange={setFetchXml} metadata={metadata} />;
}
Blazor n’a pas besoin de câblage : <FetchXmlBuilder> il résout le service de métadonnées du portail lui-même et lit les mêmes points de terminaison mis en cache, donc ses sélectionneurs partagent aussi ce que les grilles sur la page ont déjà récupéré.
@* Le tableau, les colonnes et les relations viennent de l’environnement *@
<FetchXmlBuilder @bind-FetchXml="_fetchXml" />
Le constructeur analyse FetchXML dans un modèle de document et le réécrit. Tout ce pour quoi il n’a pas d’éditeur — un attribut d’une version plus récente de la plateforme, un élément écrit par un autre outil — est conservé sans être modifié plutôt que supprimé au chargement, donc ouvrir une requête dans l’éditeur et l’enregistrer ne vous coûte jamais une partie discrètement.
Ce que cela signifie pour une requête sauvegardée
La mise en forme n’est pas préservée. L’indentation et la citation des attributs sont normalisées à la sortie, donc une requête resauvegardée via le constructeur est la même requête plutôt que le même texte.
Il y a trois entrées, et toutes trois passent par le même lecteur :
value . Fournissez-la onChange pour un composant contrôlé, ou utilisez-la defaultValue et laissez le constructeur s’approprier son état.Tout ce qui arrive est vérifié en premier. Un XML mal formé est signalé avec sa ligne et sa colonne, tout comme tout ce qui ferait afficher à l’éditeur autre chose que ce qui a été écrit — un opérateur ou un type de lien qu’il ne connaît pas, une requête ne nommant aucune table. Ces éléments sont catégoriquement refusés et la requête déjà à l’écran est laissée intacte. Tout le reste est rapporté et toujours appliqué : un élément ou un attribut mal orthographié, deux tables partageant un alias, une condition litue d’un alias que rien ne déclare.
Une jointure est ajoutée à partir du sélecteur de relations, donc les from colonnes et to proviennent de la relation plutôt que de la mémoire. Ce qu’une jointure peut alors apporter dépend de son type :
inner, outer et matchfirstrowusingcrossapply — ramènent les colonnes de la table associée, afin que leurs colonnes puissent être projetées, triées et comparées.exists, in, any, not any et all — retournent la ligne au maximum une fois et aucune des colonnes associées. L’éditeur supprime l’alias lorsque vous en basculez, donc le nom est libre pour une autre jointure.À propos de « tous »
FetchXML
allne signifie pas ce que son nom suggère — il correspond à des lignes dont les lignes sont apparentées dont aucune ne satisfait au filtre, etnot allest documenté comme équivalent àany. Chaque type est étiqueté selon son rôle plutôt que son nom, et une action Invert conditions sur un groupe de filtres exprime la lecture que les gens souhaitent généralement.
Un filtre est un groupe de conditions combinées avec et ou ou, et les groupes s’imbriquent les uns dans les autres à la profondeur dont la requête a besoin. Quatre éléments de l’arbre valent la peine d’être connus, car chacun répond à une question que FetchXML rend difficile à poser :
all cela ne signifie pas « toutes les lignes apparentées correspondent » — il correspond aux lignes dont aucune ligne apparentée ne satisfait pas au filtre — donc exprimer la lecture intuitive signifie d’abord inverser. Elle est proposée uniquement lorsque chaque condition ci-dessous a un véritable opposé ; la plupart des opérateurs de date n’en ont aucun, et inverser une partie d’un filtre semblerait inversée et correspondrait aux mauvaises lignes.valueofFetchXML Six opérateurs le permettent et la plateforme refuse catégoriquement le reste, donc la liste des opérateurs se rétrécit tant que la ligne est dans ce mode. Les candidats proviennent de chaque table jointe, puisqu’une condition atteint une colonne apparentée en nommant l’alias de la jointure.Rangées qui ne sont pas encore terminées
Une condition manquant de la valeur dont son opérateur a besoin est esquissée, tout comme un alias requis et vide, ou partagé avec une autre colonne. Les trois produisent FetchXML qui analyse parfaitement puis échoue — ou renvoie silencieusement les mauvaises lignes — donc l’éditeur le dit plutôt que de le laisser être trouvé lors de l’exécution de la requête. Les opérateurs qui n’ont pas besoin de valeur, tels que
Contains dataetToday, sont complets seuls et ne sont jamais marqués.
Activez l’agrégat dans la section Colonnes et chaque colonne indique ce qu’elle apporte — une valeur calculée sur les lignes, ou la chose qui les regroupe. Les fonctions proposées se resserrent au type de la colonne, les alias deviennent nécessaires et sont remplis pour vous, une colonne de date groupée gagne une partie date, et le tri change vers les alias, car les lignes d’une requête agrégée sont des groupes et des valeurs calculées sans colonnes à trier.
<fetch aggregate="true">
<entity name="account">
<attribute name="revenue" alias="sum_revenue" aggregate="sum" />
<attribute name="address1_city" alias="group_address1_city" groupby="true" />
<order alias="group_address1_city" />
</entity>
</fetch>
allowAggregate={false} retire le commutateur, pour un hôte qui lit les lignes plutôt que les totaux — une règle évaluée un enregistrement à la fois, un filtre sauvegardé, n’importe où une seule ligne de valeurs calculées ne serait pas une réponse. Elle est absente plutôt que désactivée, car aucun changement de requête ne la ramènerait. La seule exception est une requête qui s’agrége déjà : elle conserve ses contrôles quel que soit le réglage du prop, donc une requête collée dans le panneau FetchXML peut toujours être modifiée en une requête ordinaire.
// Le commutateur Aggregate n’est pas proposé du tout.
<FetchXmlBuilder
metadata={metadata}
table="contact"
allowAggregate={false}
value={fetchXml}
onChange={setFetchXml}
/>
AllowAggregate="false" fait de même sur Blazor, à la même exception : une requête qui agrège déjà conserve ses contrôles, donc une requête collée dans l’onglet FetchXML peut toujours être modifiée en une requête ordinaire.
@* Retirez le commutateur agrégé *@
<FetchXmlBuilder Table="contact"
AllowAggregate="false"
@bind-FetchXml="_fetchXml" />
Chaque section peut être désactivée, et les sections sont exportées individuellement pour une mise en page qui en a besoin ailleurs — montez <FetchXmlBuilderProvider> et placez vous-même les FetchXml*Section composants. Omettre une section supprime son interface, jamais le FetchXML sous-jacent : les colonnes d’une requête survivent intactes avec columns: false.
// Un éditeur de règles uniquement filtré, épinglé sur une seule table.
<FetchXmlBuilder
metadata={metadata}
table="contact"
sections={{ table: false, columns: false, sorts: false, options: false }}
value={fetchXml}
onChange={setFetchXml}
/>
Blazor prend le même ensemble comme un Sections enregistrement, et les sections sont des composants à part entière — cascade a FetchXmlBuilderState et place les FetchXml*Section composants là où une disposition en a besoin. Cacher-en un supprime son éditeur et jamais la requête qui le suit.
@* Afficher uniquement l’éditeur de filtres *@
<FetchXmlBuilder Table="contact"
Sections="_filterOnly"
@bind-FetchXml="_fetchXml" />
@code {
private readonly FetchXmlBuilderSections _filterOnly = new()
{
Table = false, Columns = false, Sorts = false, Options = false,
};
}
allowedTables Réduit le sélecteur de table aux noms logiques que vous listez — pour une surface qui n’a pas à interroger tout l’environnement, comme un constructeur de rapports sur la poignée de tables qu’un portail expose. Omettez-le et chaque table est proposée. Cela réduit ce qui peut être choisi, pas ce qui peut être montré : une requête qui nomme déjà une table en dehors de la liste la conserve plutôt que d’être réécrite silencieusement, et une table apparentée est toujours nommée par son nom d’affichage chaque fois qu’une jointure la mentionne. Les jointures elles-mêmes ne sont pas restreintes, car elles suivent des relations — une propriété de la table déjà choisie.
// Le sélectionneur ne propose ces trois et rien d’autre.
<FetchXmlBuilder
metadata={metadata}
allowedTables={['account', 'contact', 'opportunity']}
value={fetchXml}
onChange={setFetchXml}
/>
AllowedTables est l’équivalent de Blazor, et réduit ce qui peut être choisi plutôt que ce qui peut être montré exactement de la même manière.
@* Proposez trois tables et aucune autre *@
<FetchXmlBuilder AllowedTables="_tables"
@bind-FetchXml="_fetchXml" />
@code {
private readonly string[] _tables = ["account", "contact", "opportunity"];
}
Fournit renderResults et le constructeur développe un panneau Résultats avec un bouton Exécuter, et décide quand il peut être pressé : une fois que la requête nomme une table et ses colonnes, et qu’aucun champ n’est marqué en rouge. Afficher les lignes prend un client de données que le constructeur n’a délibérément pas, donc ce résultat vous appartient — sur un portail, cela signifie généralement celui du <MainGrid> framework sur la requête qu’il renvoie. Laissez le prop désactivé et le panneau n’est pas là.
<FetchXmlBuilder
metadata={metadata}
value={fetchXml}
onChange={setFetchXml}
// Le constructeur fournit le bouton ; cela indique à quoi ressemble un résultat.
renderResults={(runnable) => (
<MainGrid
key={runnable.fetchXml}
tableName={runnable.tableName}
customViewDefinitions={[{
id: BUILDER_VIEW_ID,
displayName: 'Builder query',
tableName: runnable.tableName,
fetchXml: runnable.fetchXml,
columns: runnable.columns.map((columnName) => ({ columnName, width: 200 })),
}]}
viewId={BUILDER_VIEW_ID}
/>
)}
/>
Sur Blazor, le même panneau apparaît une fois qu’un RenderResults fragment est fourni, et la requête exécutable qu’il renvoie porte la table, le FetchXML et les noms sous lesquels les colonnes reviennent. Si on laisse le fragment de côté, il n’y a pas de panneau.
@* Le constructeur possède le bouton Run ; les rangées sont à vous de tirer *@
<FetchXmlBuilder @bind-FetchXml="_fetchXml">
<RenderResults Context="runnable">
<MainGrid TableName="@runnable.TableName"
CustomViewDefinitions="@BuilderView(runnable)"
ViewIds="[BuilderViewId]" />
</RenderResults>
</FetchXmlBuilder>
@code {
private static readonly Guid BuilderViewId = Guid.Parse("00000000-0000-0000-0000-00000000f001");
private static List<GridViewDefinition> BuilderView(FetchXmlRunnableQuery runnable) =>
[
new()
{
Id = BuilderViewId,
DisplayName = "Builder query",
TableName = runnable.TableName,
FetchXml = runnable.FetchXml,
Columns = [.. runnable.Columns.Select(x => new ViewColumn { ColumnName = x, Width = 200 })],
},
];
}
Nom | Type | Par défaut | Description |
|---|---|---|---|
AllowAggregate | bool | True | Si la requête peut s’agréger ? Masquer l’offre alors qu’elle ne peut pas être réunie. |
AllowedTables | IReadOnlyList<string>? | Les seules tables proposées par le picker, ou rien pour toutes. | |
FetchXml | string? | La requête en cours de modification. | |
ReadOnly | bool | False | Affiche la requête sans proposer de la modifier. |
RenderResults | RenderFragment<FetchXmlRunnableQuery>? | Dessine les lignes renvoyées par la requête, ce qui ajoute aussi la section résultats. | |
Sections | FetchXmlBuilderSections | Quelles sections montrer. Tout sauf les résultats, qui ont besoin d’un endroit pour les dessiner. | |
ShowLogicalNames | bool | True | Que les tableaux et colonnes soient nommés avec leurs noms logiques à côté de leur nom d’affichage — |
Table | string? | Épingle la requête sur une seule table, donc le sélecteur de table est affiché mais désactivé. |
AllowAggregateAllowedTablesFetchXmlReadOnlyRenderResultsSectionsShowLogicalNamesTableNom | Type | Description |
|---|---|---|
FetchXmlChanged | EventCallback<string> | Affiché chaque fois qu’une modification modifie la requête. |
FetchXmlChanged