<FetchXmlBuilder> bearbeitet eine FetchXML-Abfrage, ohne dass jemand FetchXML schreibt. Es deckt die Teile der Sprache ab, auf die die Menschen tatsächlich zugreifen – die Tabelle, die zurückgegebenen Spalten, wie die Zeilen sortiert sind, und einen Filterbaum mit Bedingungen und verschachtelten Gruppen – und fügt zugehörige Tabellen hinzu, Aggregate und führt das aus, was es gebaut hat.
Die eigentliche Komponente im Vergleich zu den Metadaten dieser Umgebung. Wähle eine Tabelle, füge eine Spalte oder eine Bedingung hinzu, joine eine zugehörige Tabelle und beobachte, wie das FetchXML-Panel Schritt hält – dann drücke Ausführen, um zu sehen, was die Abfrage übereinstimmt.
Nicht dasselbe wie FetchXMLBuilder
Diese Seite handelt von der Komponente.
FetchXMLBuilderist die C#-Klasse, die dasselbe XML im Code zusammensetzt, für einen serverseitigen Aufrufer, der eine Abfrage manuell erstellt. Sie erzeugen das Gleiche und keiner benötigt den anderen.
Jede Tabelle, Spalte und Beziehung wird aus dem ausgewählt, was die Umgebung tatsächlich hat. Das ist beabsichtigt: Ein logischer Name, der von Hand getippt wird, erzeugt FetchXML, das perfekt analysiert wird und dann gegen Dataverse fehlschlägt, was die schlimmste Art von Fehler ist, die man jemandem geben kann. Der usePowerPortalsProFetchXmlMetadata Haken verbindet den Builder mit den zwischengespeicherten Metadaten-Endpunkten des Frameworks, sodass die Picker alles teilen, was die Raster auf derselben Seite bereits abgerufen haben.
// Die gesamte Verkabelung auf einer Portalseite.
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 benötigt keine Verdrahtung: <FetchXmlBuilder> Es löst den Metadatendienst des Portals selbst auf und liest dieselben zwischengespeicherten Endpunkte, sodass seine Picker auch das teilen, was die Raster auf der Seite bereits abgerufen haben.
@* Die Tabelle, Spalten und Beziehungen stammen aus der Umgebung *@
<FetchXmlBuilder @bind-FetchXml="_fetchXml" />
Der Builder parst FetchXML in ein Dokumentmodell und schreibt es wieder heraus. Alles, wofür er keinen Editor hat – ein Attribut einer neueren Plattformversion, ein von einem anderen Tool geschriebenes Element – wird unberührt durchgetragen, anstatt beim Laden fallen zu lassen, sodass das Öffnen einer Abfrage im Editor und das Speichern eines Abschnitts nie einen Teil davon kostet.
Was das für eine gespeicherte Abfrage bedeutet
Die Formatierung bleibt nicht erhalten. Einzug und Attributquotierung werden beim Herausgehen normalisiert, sodass eine im Builder erneut gespeicherte Abfrage dieselbe Anfrage ist und nicht derselbe Text.
Es gibt drei Zugänge, und alle drei laufen über denselben Leser:
value . Liefern Sie sie onChange für eine kontrollierte Komponente oder verwenden defaultValue Sie sie und lassen Sie den Bauherren über ihren Zustand verfügen.Was auch immer eintrifft, wird zuerst überprüft. Fehlgeformtes XML wird mit Zeile und Spalte gemeldet, ebenso alles, was den Editor dazu bringen würde, etwas anderes anzuzeigen als das, was geschrieben wurde – einen Operator oder Linktyp, den er nicht kennt, eine Abfrage, die keine Tabelle nennt. Diese werden komplett abgelehnt und die bereits auf dem Bildschirm befindliche Abfrage bleibt unverändert. Alles andere wird gemeldet und weiterhin angewendet: ein falsch geschriebenes Element oder Attribut, zwei Tabellen mit gemeinsamem Alias, eine Bedingung, die von einem Alias liest, nichts deklariert.
Ein Join wird vom Beziehungspicker hinzugefügt, sodass die from Spalten und to aus der Beziehung stammen und nicht aus dem Speicher. Was ein Join dann beitragen kann, hängt von seinem Typ ab:
inner, und matchfirstrowusingcrossapply outer — bringen die Spalten der zugehörigen Tabelle zurück, sodass ihre Spalten projiziert, sortiert und verglichen werden können.exists, , inany, und not any all — geben die Zeile höchstens einmal zurück und keine der zugehörigen Spalten. Der Editor lässt den Alias fallen, wenn man zu einem Alias, sodass der Name für einen weiteren Beitritt frei ist.Über "alle"
FetchXML bedeutet nicht das, was sein Name vermuten lässt – es ordnet Zeilen ab, die verwandte Zeilen
allhaben , von denen keine den Filter erfüllt, undnot allwird als äquivalent zuanydokumentiert. Jeder Typ wird nach seiner Funktion und nicht nach seinem Namen beschriftet, und eine Invert conditions-Aktion in einer Filtergruppe drückt die Lesung aus, die die Leute normalerweise wollen.
Ein Filter ist eine Gruppe von Bedingungen, kombiniert mit und/ oder oder, und Gruppen verschachtelt sich in der Tiefe, die die Abfrage benötigt. Vier Dinge im Baum sind es wert, darüber zu wissen, denn jede beantwortet eine Frage, die FetchXML unangenehm macht:
all bedeutet nicht "jede verwandte Zeile stimmt überein" – es stimmt Zeilen ab, deren verwandte Zeilen den Filter nicht erfüllen – daher bedeutet das Ausdrücken der intuitiven Lesart das Invertieren zuerst. Es wird nur angeboten, wenn jede Bedingung unten ein echtes Gegenteil hat; die meisten Datumsoperatoren haben keine, und das Invertieren eines Filters würde invertiert aussehen und die falschen Zeilen übereinstimmen.valueoferlauben dies und die Plattform lehnt den Rest komplett ab, sodass die Operatorenliste sich verengt, während die Zeile in diesem Modus ist. Kandidaten stammen aus jeder joined-Tabelle, da eine Bedingung eine verwandte Spalte erreicht, indem sie das Join-Alias benennen.Reihen, die noch nicht fertig sind
Eine Bedingung, der den Wert fehlt, den sein Operator benötigt, wird umrissen, ebenso wie ein Alias, das erforderlich und leer ist oder mit einer anderen Spalte geteilt wird. Alle drei erzeugen FetchXML, das perfekt parsiert und dann fehlschlägt – oder still die falschen Zeilen zurückgibt –, sodass der Editor dies sagt, anstatt es beim Ausführen der Abfrage finden zu lassen. Operatoren, die keinen Wert benötigen, wie
Contains dataundToday, sind für sich allein vollständig und werden nie markiert.
Schalten Sie im Abschnitt Spalten Aggregate ein, und jede Spalte gibt an, was sie beiträgt – ein Wert, der über die Zeilen berechnet wird, oder das Element, nach dem sie gruppiert sind. Die angebotenen Funktionen verengen sich auf den Typ der Spalte, Aliase werden benötigt und werden für Sie ausgefüllt, eine gruppierte Datumsspalte erhält einen Datumsteil, und das Sortieren wechselt zu den Aliasen, weil die Zeilen einer aggregierten Abfrage Gruppen und berechnete Werte ohne Spalten zum Sortieren sind.
<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} zieht den Switch zurück, für einen Host, der Zeilen statt Totalen liest – eine Regel, die jeweils einen Datensatz bewertet, ein gespeicherter Filter, überall dort, wo eine einzelne Zeile berechneter Werte aussieht, wäre keine Antwort. Sie ist abwesend und nicht deaktiviert, da keine Änderung der Abfrage sie zurückbringen würde. Die eine Ausnahme ist eine Abfrage, die bereits aggregiert: Sie behält ihre Kontrollen, wie auch immer der Prop gesetzt ist, sodass eine, die in das FetchXML-Panel eingefügt wurde, weiterhin in eine gewöhnliche Abfrage zurückbearbeitet werden kann.
// Der Aggregate-Schalter wird überhaupt nicht angeboten.
<FetchXmlBuilder
metadata={metadata}
table="contact"
allowAggregate={false}
value={fetchXml}
onChange={setFetchXml}
/>
AllowAggregate="false" das Gleiche auf Blazor, mit derselben Ausnahme: Eine Abfrage, die bereits aggregiert, behält ihre Steuerungen, sodass eine, die in den FetchXML-Tab eingefügt wurde, weiterhin in eine gewöhnliche Abfrage zurückbearbeitet werden kann.
@* Ziehen Sie den Aggregatschalter zurück *@
<FetchXmlBuilder Table="contact"
AllowAggregate="false"
@bind-FetchXml="_fetchXml" />
Jeder Abschnitt kann ausgeschaltet werden, und die Abschnitte werden einzeln exportiert für ein Layout, das sie woanders benötigt – mounten <FetchXmlBuilderProvider> und platzieren Sie die FetchXml*Section Komponenten selbst. Das Weglassen eines Abschnitts entfernt dessen Benutzeroberfläche, niemals das zugrundeliegende FetchXML: Die Spalten einer Abfrage überleben unberührt mit columns: false.
// Ein reiner Filter-Regeleditor, der an eine Tabelle angepinnt ist.
<FetchXmlBuilder
metadata={metadata}
table="contact"
sections={{ table: false, columns: false, sorts: false, options: false }}
value={fetchXml}
onChange={setFetchXml}
/>
Blazor verwendet denselben Satz wie ein Sections Datensatz, und die Abschnitte sind eigenständige Komponenten – Kaskaden-a FetchXmlBuilderState und Platzierung der FetchXml*Section Komponenten dort, wo ein Layout sie braucht. Das Ausstecken eines entfernt den Editor und nie die dahinterliegende Abfrage.
@* Zeigt den Filter-Editor allein an *@
<FetchXmlBuilder Table="contact"
Sections="_filterOnly"
@bind-FetchXml="_fetchXml" />
@code {
private readonly FetchXmlBuilderSections _filterOnly = new()
{
Table = false, Columns = false, Sorts = false, Options = false,
};
}
allowedTables schränkt den Tabellenwähler auf die logischen Namen ein, die du auflistest – für eine Oberfläche, die keine Aufgabe hat, die gesamte Umgebung abzufragen, wie ein Report Builder über die wenigen Tabellen, die ein Portal offenstellt. Lässt man es weg, wird jede Tabelle angeboten. Es schränkt ein, was ausgewählt werden kann, nicht was gezeigt werden kann: Eine Abfrage, die bereits eine Tabelle außerhalb der Liste nennt, behält sie, anstatt still umgeschrieben zu werden, und eine verwandte Tabelle wird immer noch nach ihrem Anzeigenamen benannt, wo ein Join sie erwähnt. Joins selbst sind nicht eingeschränkt, da sie Beziehungen folgen – eine Eigenschaft der bereits gewählten Tabelle.
// Der Picker bietet diese drei und sonst nichts.
<FetchXmlBuilder
metadata={metadata}
allowedTables={['account', 'contact', 'opportunity']}
value={fetchXml}
onChange={setFetchXml}
/>
AllowedTables ist das Blazor-Äquivalent und schränkt ein, was gewählt werden kann, statt das, was auf genau dieselbe Weise gezeigt werden kann.
@* Bieten Sie drei Tische an und keine weiteren *@
<FetchXmlBuilder AllowedTables="_tables"
@bind-FetchXml="_fetchXml" />
@code {
private readonly string[] _tables = ["account", "contact", "opportunity"];
}
Liefert renderResults und der Builder erstellt ein Ergebnispanel mit einem Ausführen-Button und entscheidet, wann es gedrückt werden darf: sobald die Abfrage eine Tabelle und ihre Spalten benannt hat und kein Feld rot markiert ist. Das Anzeigen von Zeilen erfordert einen Datenclient, von dem der Builder absichtlich keinen hat, sodass ein Ergebnis Ihres Aussehens ist – auf einem Portal bedeutet das meist das eigene <MainGrid> Framework über die zurückgegebene Abfrage. Lassen Sie den Prop aus, und das Panel ist nicht mehr vorhanden.
<FetchXmlBuilder
metadata={metadata}
value={fetchXml}
onChange={setFetchXml}
// Der Erbauer stellt den Knopf zur Verfügung; hier steht, wie ein Ergebnis aussieht.
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}
/>
)}
/>
Bei Blazor erscheint dasselbe Panel, sobald ein RenderResults Fragment bereitgestellt wurde, und die ausführbare Abfrage, die es zurückgibt, enthält die Tabelle, FetchXML und die Namen, unter denen die Spalten zurückkommen. Lässt man das Fragment weg, gibt es kein Panel.
@* Der Erbauer besitzt die Lauf-Taste; die Zeilen gehören dir zum Zeichnen *@
<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 })],
},
];
}
Name | Typ | Default | Beschreibung |
|---|---|---|---|
AllowAggregate | bool | True | Ob die Anfrage aggregiert werden könnte. Verbirgt das Angebot, wenn es nicht sein könnte. |
AllowedTables | IReadOnlyList<string>? | Die einzigen Tische, die der Plücker anbietet, oder für alle nichts. | |
FetchXml | string? | Die Anfrage wird bearbeitet. | |
ReadOnly | bool | False | Zeigt die Abfrage an, ohne anzubieten, sie zu ändern. |
RenderResults | RenderFragment<FetchXmlRunnableQuery>? | Zeichnet die Zeilen, die die Abfrage zurückgegeben hat, was auch den Ergebnisbereich hinzufügt. | |
Sections | FetchXmlBuilderSections | Welche Abschnitte gezeigt werden sollen. Alles außer den Ergebnissen, die irgendwo zu sehen sind. | |
ShowLogicalNames | bool | True | Ob Tabellen und Spalten mit ihren logischen Namen neben ihren Anzeigenamen benannt werden – |
Table | string? | Heftet die Abfrage an eine Tabelle, sodass der Tabellenwähler angezeigt, aber deaktiviert ist. |
AllowAggregateAllowedTablesFetchXmlReadOnlyRenderResultsSectionsShowLogicalNamesTableName | Typ | Beschreibung |
|---|---|---|
FetchXmlChanged | EventCallback<string> | Es wird angezeigt, wann immer eine Änderung die Abfrage ändert. |
FetchXmlChanged