Megosztás a következőn keresztül:


TripPin 10. rész – Egyszerű lekérdezés-összecsukás

Feljegyzés

Ez a tartalom jelenleg egy örökölt implementációból származó tartalmakra hivatkozik a Visual Studióban lévő naplókhoz. A tartalom a közeljövőben frissülni fog, hogy lefedje a Visual Studio Code új Power Query SDK-ját.

Ez a többrészes oktatóanyag a Power Query új adatforrásbővítményének létrehozását ismerteti. Az oktatóanyagot egymás után kell elvégezni – minden lecke az előző leckékben létrehozott összekötőre épül, és növekményesen új képességeket ad hozzá az összekötőhöz.

Ebben a leckében a következőt fogja:

  • A lekérdezések összecsukásának alapjai
  • További információ a Table.View függvényről
  • OData-lekérdezés összecsukható kezelőinek replikálása a következőhöz:
  • $top
  • $skip
  • $count
  • $select
  • $orderby

Az M nyelv egyik hatékony funkciója, hogy képes leküldni az átalakítást egy vagy több mögöttes adatforrásba. Ezt a képességet lekérdezés-összecsukásnak nevezzük (más eszközök/technológiák is hasonló függvényre hivatkoznak, mint a Predicate Pushdown vagy a Query Delegálás).

Ha olyan egyéni összekötőt hoz létre, amely beépített lekérdezés-összecsukási képességekkel (például OData.Feed vagy Odbc.DataSource) rendelkező M függvényt használ, az összekötő automatikusan ingyenesen örökli ezt a képességet.

Ez az oktatóanyag replikálja az OData beépített lekérdezés-összecsukási viselkedését a Table.View függvény függvénykezelőinek implementálásával. Az oktatóanyag ezen része implementálja a könnyebben implementálható kezelők némelyikét (vagyis azokat, amelyek nem igényelnek kifejezés-elemzést és állapotkövetést).

Az OData-szolgáltatás által kínált lekérdezési képességekről az OData v4 URL-konvenciók című témakörben olvashat bővebben.

Feljegyzés

Ahogy korábban említettem, az OData.Feed függvény automatikusan biztosít lekérdezés-összecsukási képességeket. Mivel a TripPin-sorozat az OData szolgáltatást normál REST API-ként kezeli, az OData.Feed helyett a Web.Contents szolgáltatást használja, saját maga kell implementálnia a lekérdezés-összecsukható kezelőket. Valós használat esetén javasoljuk, hogy az OData.Feedet használja, amikor csak lehetséges.

A lekérdezések összecsukásával kapcsolatos további információkért tekintse meg a lekérdezések kiértékelésének és a lekérdezések összecsukásának áttekintését a Power Queryben .

A Table.View használata

A Table.View függvény lehetővé teszi, hogy egy egyéni összekötő felülírja az adatforrás alapértelmezett átalakítási kezelőinek értékét. A Table.View implementációja egy vagy több támogatott kezelőhöz biztosít függvényt. Ha egy kezelő nem működik, vagy a kiértékelés során ad vissza egy error hibát, az M motor visszaáll az alapértelmezett kezelőre.

Ha egy egyéni összekötő olyan függvényt használ, amely nem támogatja az implicit lekérdezések összecsukását(például Web.Contents), az alapértelmezett átalakítási kezelők mindig helyben lesznek végrehajtva. Ha a lekérdezés részeként a lekérdezés részeként a lekérdezési paramétereket támogató REST API-hoz csatlakozik, a Table.View lehetővé teszi olyan optimalizálások hozzáadását, amelyek lehetővé teszik az átalakítási munka leküldését a szolgáltatásba.

A Table.View függvény a következő aláírással rendelkezik:

Table.View(table as nullable table, handlers as record) as table

Az implementáció körbefuttatja a fő adatforrásfüggvényt. A Table.View két szükséges kezelőt tartalmaz:

  • GetType— a lekérdezés eredményének várt table type értékét adja vissza
  • GetRows— az adatforrásfüggvény tényleges table eredményét adja vissza

A legegyszerűbb implementáció a következő példához hasonló:

TripPin.SuperSimpleView = (url as text, entity as text) as table =>
    Table.View(null, [
        GetType = () => Value.Type(GetRows()),
        GetRows = () => GetEntity(url, entity)
    ]);

Frissítse a függvényt TripPinNavTable a következő helyett hívásra TripPin.SuperSimpleViewGetEntity:

withData = Table.AddColumn(rename, "Data", each TripPin.SuperSimpleView(url, [Name]), type table),

Ha újrafuttatja az egységteszteket, láthatja, hogy a függvény működése nem változik. Ebben az esetben a Table.View implementáció egyszerűen áthalad a híváson GetEntity. Mivel még nem implementált átalakítási kezelőket (még), az eredeti url paraméter érintetlen marad.

A Table.View kezdeti implementálása

A Table.View fenti implementációja egyszerű, de nem túl hasznos. A következő implementációt használja alapkonfigurációként – nem implementál összecsukható funkciókat, de rendelkezik a szükséges állványzatkal.

TripPin.View = (baseUrl as text, entity as text) as table =>
    let
        // Implementation of Table.View handlers.
        //
        // We wrap the record with Diagnostics.WrapHandlers() to get some automatic
        // tracing if a handler returns an error.
        //
        View = (state as record) => Table.View(null, Diagnostics.WrapHandlers([
            // Returns the table type returned by GetRows()
            GetType = () => CalculateSchema(state),

            // Called last - retrieves the data from the calculated URL
            GetRows = () => 
                let
                    finalSchema = CalculateSchema(state),
                    finalUrl = CalculateUrl(state),

                    result = TripPin.Feed(finalUrl, finalSchema),
                    appliedType = Table.ChangeType(result, finalSchema)
                in
                    appliedType,

            //
            // Helper functions
            //
            // Retrieves the cached schema. If this is the first call
            // to CalculateSchema, the table type is calculated based on
            // the entity name that was passed into the function.
            CalculateSchema = (state) as type =>
                if (state[Schema]? = null) then
                    GetSchemaForEntity(entity)
                else
                    state[Schema],

            // Calculates the final URL based on the current state.
            CalculateUrl = (state) as text => 
                let
                    urlWithEntity = Uri.Combine(state[Url], state[Entity])
                in
                    urlWithEntity
        ]))
    in
        View([Url = baseUrl, Entity = entity]);

Ha megtekinti a Table.View hívását, egy további burkolófüggvény jelenik meg a handlers rekord körül –Diagnostics.WrapHandlers Ez a segédfüggvény a Diagnosztika modulban található (amely a diagnosztikai leckében lett bevezetve), és hasznos módot kínál az egyes kezelők által felmerülő hibák automatikus nyomon követésére.

Az GetType és GetRows a függvények frissülnek, hogy két új segédfüggvényt használjon–CalculateSchema és CalculateUrl. Jelenleg ezeknek a függvényeknek a implementációi meglehetősen egyszerűek – figyelje meg, hogy azok a függvény által GetEntity korábban elvégzett műveletek részeit tartalmazzák.

Végül figyelje meg, hogy egy olyan belső függvényt (View) definiál, amely elfogadja a paramétert state . A további kezelők implementálása során rekurzív módon meghívják a belső View függvényt, és folyamatosan frissülnek és haladnak state tovább.

Frissítse ismét a TripPinNavTable függvényt, cserélje le a hívást TripPin.SuperSimpleView az új TripPin.View függvény hívására, és futtassa újra az egységteszteket. Egyelőre nem fog új funkciókat látni, de most már rendelkezik egy szilárd alapkonfigurációval a teszteléshez.

Lekérdezés-összecsukás implementálása

Mivel az M motor automatikusan visszaesik a helyi feldolgozásra, amikor egy lekérdezés nem hajtható végre, további lépéseket kell tennie annak ellenőrzéséhez, hogy a Table.View kezelői megfelelően működnek-e.

Az összecsukható viselkedés ellenőrzésének manuális módja, ha az egységtesztek által a Fiddlerhez hasonló eszközzel végzett URL-kéréseket figyeli. Alternatív megoldásként a diagnosztikai naplózás, amelyet a TripPin.Feed teljes futtatandó URL-cím kibocsát, amelynek tartalmaznia kell a kezelők által hozzáadott OData lekérdezési sztringparamétereket.

A lekérdezés-összecsukás ellenőrzésének automatikus módja, ha az egységteszt végrehajtását sikertelenre kényszeríti, ha egy lekérdezés nem hajtja végre teljesen. Ezt úgy teheti meg, hogy megnyitja a projekt tulajdonságait, és igaz értékre állítja a sikertelen összecsukási hibát. Ha ez a beállítás engedélyezve van, a helyi feldolgozást igénylő lekérdezések a következő hibát eredményezik:

A kifejezést nem sikerült a forrásra hajtani. Próbálkozzon egyszerűbb kifejezéssel.

Ezt úgy tesztelheti, hogy hozzáad egy újat Fact az egységtesztfájlhoz, amely egy vagy több táblaátalakítást tartalmaz.

// Query folding tests
Fact("Fold $top 1 on Airlines", 
    #table( type table [AirlineCode = text, Name = text] , {{"AA", "American Airlines"}} ), 
    Table.FirstN(Airlines, 1)
)

Feljegyzés

Az Összecsukási hiba beállítás "minden vagy semmi" megközelítés. Ha olyan lekérdezéseket szeretne tesztelni, amelyek nem az egységtesztek részeként való összecsukásra vannak tervezve, a tesztek megfelelő engedélyezéséhez/letiltásához fel kell vennie néhány feltételes logikát.

Az oktatóanyag fennmaradó szakaszai mindegyike új Table.View kezelőt ad hozzá. Egy tesztalapú fejlesztési (TDD) megközelítést használ, amelyben először sikertelen egységteszteket ad hozzá, majd implementálja az M-kódot a feloldásukhoz.

Az alábbi kezelőszakaszok a kezelő által biztosított funkciókat, az OData egyenértékű lekérdezési szintaxist, az egységteszteket és az implementációt ismertetik. A korábban ismertetett állványzatkód használatával minden kezelő implementációja két módosítást igényel:

  • A rekordot frissítő kezelő hozzáadása a state Table.View nézethez.
  • CalculateUrl Módosítás az értékek lekéréséhez és state az URL-címhez és/vagy a lekérdezési sztring paramétereihez való hozzáadáshoz.

Table.FirstN kezelése az OnTake-nal

A OnTake kezelő egy paramétert count kap, amely az átveendő GetRowssorok maximális száma. OData-kifejezésekben ezt lefordíthatja a $top lekérdezési paraméterre.

A következő egységteszteket használja:

// Query folding tests
Fact("Fold $top 1 on Airlines", 
    #table( type table [AirlineCode = text, Name = text] , {{"AA", "American Airlines"}} ), 
    Table.FirstN(Airlines, 1)
),
Fact("Fold $top 0 on Airports", 
    #table( type table [Name = text, IataCode = text, Location = record] , {} ), 
    Table.FirstN(Airports, 0)
),

Ezek a tesztek a Table.FirstN használatával szűrnek az eredményhalmazra az első X számú sorra. Ha az összecsukási hiba hiba beállításával False futtatja ezeket a teszteket (alapértelmezés szerint), a teszteknek sikeresnek kell lennie, de ha a Fiddlert futtatja (vagy ellenőrzi a nyomkövetési naplókat), figyelje meg, hogy az elküldött kérés nem tartalmaz OData-lekérdezési paramétereket.

Diagnosztikai nyomkövetés.

Ha az összecsukási hiba hibátTrueállítja be, a tesztek a hibával Please try a simpler expression. meghiúsulnak. A hiba elhárításához meg kell adnia az első Table.View kezelőt a következőhöz OnTake: .

A OnTake kezelő a következő kódhoz hasonlóan néz ki:

OnTake = (count as number) =>
    let
        // Add a record with Top defined to our state
        newState = state & [ Top = count ]
    in
        @View(newState),

A CalculateUrl függvény frissül, hogy kinyerje az Top értéket a state rekordból, és állítsa be a megfelelő paramétert a lekérdezési sztringben.

// Calculates the final URL based on the current state.
CalculateUrl = (state) as text => 
    let
        urlWithEntity = Uri.Combine(state[Url], state[Entity]),

        // Uri.BuildQueryString requires that all field values
        // are text literals.
        defaultQueryString = [],

        // Check for Top defined in our state
        qsWithTop =
            if (state[Top]? <> null) then
                // add a $top field to the query string record
                defaultQueryString & [ #"$top" = Number.ToText(state[Top]) ]
            else
                defaultQueryString,

        encodedQueryString = Uri.BuildQueryString(qsWithTop),
        finalUrl = urlWithEntity & "?" & encodedQueryString
    in
        finalUrl

Az egységtesztek újrafuttatásakor figyelje meg, hogy az ön által elért URL-cím tartalmazza a paramétert $top . Az URL-kódolás miatt úgy jelenik meg, $top mint %24top, de az OData szolgáltatás elég intelligens ahhoz, hogy automatikusan konvertálja.

Diagnosztikák nyomkövetése felülről.

A Table.Skip kezelése az OnSkip használatával

A OnSkip kezelő nagyon hasonlít OnTake. Egy paramétert count kap, amely az eredményhalmazból kihagyandó sorok száma. Ez a kezelő szépen lefordítja az OData $skip lekérdezési paramétert.

Egységtesztek:

// OnSkip
Fact("Fold $skip 14 on Airlines",
    #table( type table [AirlineCode = text, Name = text] , {{"EK", "Emirates"}} ), 
    Table.Skip(Airlines, 14)
),
Fact("Fold $skip 0 and $top 1",
    #table( type table [AirlineCode = text, Name = text] , {{"AA", "American Airlines"}} ),
    Table.FirstN(Table.Skip(Airlines, 0), 1)
),

Implementálás:

// OnSkip - handles the Table.Skip transform.
// The count value should be >= 0.
OnSkip = (count as number) =>
    let
        newState = state & [ Skip = count ]
    in
        @View(newState),

A következőhöz tartozó frissítések egyeztetése CalculateUrl:

qsWithSkip = 
    if (state[Skip]? <> null) then
        qsWithTop & [ #"$skip" = Number.ToText(state[Skip]) ]
    else
        qsWithTop,

További információ: Table.Skip

Table.SelectColumns kezelése OnSelectColumns használatával

A OnSelectColumns kezelő akkor lesz meghívva, ha a felhasználó kiválasztja vagy eltávolítja az oszlopokat az eredményhalmazból. A kezelő egy értéket kap listtext , amely egy vagy több kijelölendő oszlopot jelöl.

OData-kifejezésekben ez a művelet a $select lekérdezési beállításhoz lesz leképezve.

Az oszlopok összecsukásának előnye akkor válik nyilvánvalóvá, ha sok oszlopot tartalmazó táblákkal foglalkozik. Az $select operátor eltávolítja a nem kijelölt oszlopokat az eredményhalmazból, ami hatékonyabb lekérdezéseket eredményez.

Egységtesztek:

// OnSelectColumns
Fact("Fold $select single column", 
    #table( type table [AirlineCode = text] , {{"AA"}} ),
    Table.FirstN(Table.SelectColumns(Airlines, {"AirlineCode"}), 1)
),
Fact("Fold $select multiple column", 
    #table( type table [UserName = text, FirstName = text, LastName = text],{{"russellwhyte", "Russell", "Whyte"}}), 
    Table.FirstN(Table.SelectColumns(People, {"UserName", "FirstName", "LastName"}), 1)
),
Fact("Fold $select with ignore column", 
    #table( type table [AirlineCode = text] , {{"AA"}} ),
    Table.FirstN(Table.SelectColumns(Airlines, {"AirlineCode", "DoesNotExist"}, MissingField.Ignore), 1)
),

Az első két teszt különböző számú oszlopot jelöl ki a Table.SelectColumns használatával, és egy Table.FirstN-hívást is tartalmaz a teszteset egyszerűsítése érdekében.

Feljegyzés

Ha a teszt csak az oszlopneveket adja vissza (a Table.ColumnNames használatával, nem pedig adatokkal, akkor a rendszer soha nem küldi el a kérelmet az OData szolgáltatásnak. Ennek az az oka, hogy GetType a hívás visszaadja a sémát, amely tartalmazza az M motor által az eredmény kiszámításához szükséges összes információt.

A harmadik teszt a MissingField.Ignore lehetőséget használja, amely arra utasítja az M motort, hogy hagyja figyelmen kívül az eredményhalmazban nem létező kijelölt oszlopokat. A OnSelectColumns kezelőnek nem kell aggódnia ezzel a beállítással – az M motor automatikusan kezeli (vagyis a hiányzó oszlopok nem szerepelnek a columns listában).

Feljegyzés

A Table.SelectColumns(MissingField.UseNull) másik lehetőségéhez egy összekötőre van szükség a OnAddColumn kezelő implementálásához. Ezt egy későbbi leckében fogjuk elvégezni.

A megvalósítás OnSelectColumns két dolgot tesz:

  • Hozzáadja a kijelölt oszlopok listáját a state.
  • Újraszámítja az Schema értéket, hogy meg tudja állítani a megfelelő táblázattípust.
OnSelectColumns = (columns as list) =>
    let
        // get the current schema
        currentSchema = CalculateSchema(state),
        // get the columns from the current schema (which is an M Type value)
        rowRecordType = Type.RecordFields(Type.TableRow(currentSchema)),
        existingColumns = Record.FieldNames(rowRecordType),
        // calculate the new schema
        columnsToRemove = List.Difference(existingColumns, columns),
        updatedColumns = Record.RemoveFields(rowRecordType, columnsToRemove),
        newSchema = type table (Type.ForRecord(updatedColumns, false))
    in
        @View(state & 
            [ 
                SelectColumns = columns,
                Schema = newSchema
            ]
        ),

CalculateUrl frissül, hogy lekérje az oszlopok listáját az állapotból, és egyesítse őket (elválasztójellel) a $select paraméterhez.

// Check for explicitly selected columns
qsWithSelect =
    if (state[SelectColumns]? <> null) then
        qsWithSkip & [ #"$select" = Text.Combine(state[SelectColumns], ",") ]
    else
        qsWithSkip,

Table.Sort kezelése az OnSorttal

A OnSort kezelő megkapja a következő típusú rekordok listáját:

type [ Name = text, Order = Int16.Type ]

Minden rekord tartalmaz egy Name mezőt, amely az oszlop nevét jelzi, és egy Order olyan mezőt, amely egyenlő az Order.Ascending vagy a Order.Descending mezővel.

OData-kifejezésekben ez a művelet a $orderby lekérdezési beállításhoz lesz leképezve. A $orderby szintaxis az oszlop nevét követi asc , illetve desc növekvő vagy csökkenő sorrendet jelöl. Ha több oszlopra rendez, az értékek vesszővel vannak elválasztva. Ha a columns paraméter egynél több elemet tartalmaz, fontos fenntartani a megjelenítési sorrendet.

Egységtesztek:

// OnSort
Fact("Fold $orderby single column",
    #table( type table [AirlineCode = text, Name = text], {{"TK", "Turkish Airlines"}}),
    Table.FirstN(Table.Sort(Airlines, {{"AirlineCode", Order.Descending}}), 1)
),
Fact("Fold $orderby multiple column",
    #table( type table [UserName = text], {{"javieralfred"}}),
    Table.SelectColumns(Table.FirstN(Table.Sort(People, {{"LastName", Order.Ascending}, {"UserName", Order.Descending}}), 1), {"UserName"})
)

Implementálás:

// OnSort - receives a list of records containing two fields: 
//    [Name]  - the name of the column to sort on
//    [Order] - equal to Order.Ascending or Order.Descending
// If there are multiple records, the sort order must be maintained.
//
// OData allows you to sort on columns that do not appear in the result
// set, so we do not have to validate that the sorted columns are in our 
// existing schema.
OnSort = (order as list) =>
    let
        // This will convert the list of records to a list of text,
        // where each entry is "<columnName> <asc|desc>"
        sorting = List.Transform(order, (o) => 
            let
                column = o[Name],
                order = o[Order],
                orderText = if (order = Order.Ascending) then "asc" else "desc"
            in
                column & " " & orderText
        ),
        orderBy = Text.Combine(sorting, ", ")
    in
        @View(state & [ OrderBy = orderBy ]),

Frissítések:CalculateUrl

qsWithOrderBy = 
    if (state[OrderBy]? <> null) then
        qsWithSelect & [ #"$orderby" = state[OrderBy] ]
    else
        qsWithSelect,

Table.RowCount kezelése a GetRowCount használatával

A többi implementálható lekérdezéskezelővel ellentétben a GetRowCount kezelő egyetlen értéket ad vissza – az eredményhalmazban várt sorok számát. Egy M lekérdezésben ez az érték általában a Table.RowCount átalakítás eredménye.

Az OData-lekérdezések részeként többféleképpen is kezelheti ezt az értéket:

A lekérdezési paraméter megközelítésének hátránya, hogy a teljes lekérdezést továbbra is el kell küldenie az OData szolgáltatásnak. Mivel a szám az eredményhalmaz részeként visszakerül a beágyazottba, az eredményhalmaz első adatoldalát kell feldolgoznia. Bár ez a folyamat még mindig hatékonyabb, mint a teljes eredményhalmaz beolvasása és a sorok számlálása, valószínűleg még mindig több munka, mint amennyit el szeretne végezni.

Az elérésiút-szegmens megközelítésének előnye, hogy csak egyetlen skaláris értéket kap az eredményben. Ez a megközelítés sokkal hatékonyabbá teszi az egész műveletet. Az OData-specifikációban leírtak szerint azonban a /$count elérésiút-szegmens hibát ad vissza, ha más lekérdezési paramétereket is tartalmaz, például $top vagy $skip, amelyek korlátozzák annak hasznosságát.

Ebben az oktatóanyagban az GetRowCount elérésiút-szegmens megközelítésével implementálta a kezelőt. Annak érdekében, hogy elkerülje azokat a hibákat, amelyeket más lekérdezési paraméterek hozzáadásakor kap, más állapotértékeket is ellenőriz, és ha nem talált ilyen hibát, "nem sikerült hibát" (...) adott vissza. Ha hibát ad vissza a Table.View kezelőtől, az azt jelzi az M motornak, hogy a művelet nem hajtható végre, és inkább az alapértelmezett kezelőre kell visszaesnie (ami ebben az esetben a sorok teljes számát számolná).

Először adjon hozzá egy egységtesztet:

// GetRowCount
Fact("Fold $count", 15, Table.RowCount(Airlines)),

Mivel az /$count elérésiút-szegmens JSON-eredménykészlet helyett egyetlen értéket ad vissza (egyszerű/szöveges formátumban), új belső függvényt (TripPin.Scalar) is hozzá kell adnia a kérés elkészítéséhez és az eredmény kezeléséhez.

// Similar to TripPin.Feed, but is expecting back a scalar value.
// This function returns the value from the service as plain text.
TripPin.Scalar = (url as text) as text =>
    let
        _url = Diagnostics.LogValue("TripPin.Scalar url", url),

        headers = DefaultRequestHeaders & [
            #"Accept" = "text/plain"
        ],

        response = Web.Contents(_url, [ Headers = headers ]),
        toText = Text.FromBinary(response)
    in
        toText;

Az implementáció ezt a függvényt használja (ha nem található más lekérdezési paraméter a statekövetkezőben):

GetRowCount = () as number =>
    if (Record.FieldCount(Record.RemoveFields(state, {"Url", "Entity", "Schema"}, MissingField.Ignore)) > 0) then
        ...
    else
        let
            newState = state & [ RowCountOnly = true ],
            finalUrl = CalculateUrl(newState),
            value = TripPin.Scalar(finalUrl),
            converted = Number.FromText(value)
        in
            converted,

A CalculateUrl függvény úgy frissül, hogy hozzáfűzze /$count az URL-címet, ha a RowCountOnly mező be van állítva a state.

// Check for $count. If all we want is a row count,
// then we add /$count to the path value (following the entity name).
urlWithRowCount =
    if (state[RowCountOnly]? = true) then
        urlWithEntity & "/$count"
    else
        urlWithEntity,

Az új Table.RowCount egységtesztnek most meg kell felelnie.

A tartalék eset teszteléséhez adjon hozzá egy másik tesztet, amely kényszeríti a hibát.

Először adjon hozzá egy segédmetódust, amely ellenőrzi a try művelet eredményét egy összecsukási hiba esetén.

// Returns true if there is a folding error, or the original record (for logging purposes) if not.
Test.IsFoldingError = (tryResult as record) =>
    if ( tryResult[HasError]? = true and tryResult[Error][Message] = "We couldn't fold the expression to the data source. Please try a simpler expression.") then
        true
    else
        tryResult;

Ezután adjon hozzá egy olyan tesztet, amely a Table.RowCount és a Table.FirstN függvényt is használja a hiba kényszerítéséhez.

// test will fail if "Fail on Folding Error" is set to false
Fact("Fold $count + $top *error*", true, Test.IsFoldingError(try Table.RowCount(Table.FirstN(Airlines, 3)))),

Fontos megjegyezni, hogy ez a teszt most hibát ad vissza, ha az összecsukási hiba értéke be van állítva false, mert a Table.RowCount művelet visszakerül a helyi (alapértelmezett) kezelőre. A tesztek futtatása az összecsukási hiba beállítással truesikertelennek, Table.RowCount és lehetővé teszi a teszt sikerességét.

Összegzés

Az összekötő Table.View implementálása jelentősen összetettebbé teszi a kódot. Mivel az M motor képes az összes átalakítás helyi feldolgozására, a Table.View kezelők hozzáadása nem teszi lehetővé az új forgatókönyveket a felhasználók számára, de hatékonyabb feldolgozást (és potenciálisan boldogabb felhasználókat) eredményez. A Table.View kezelők opcionális használatának egyik fő előnye, hogy lehetővé teszi az új funkciók növekményes hozzáadását anélkül, hogy az hatással lenne az összekötő visszamenőleges kompatibilitására.

A legtöbb összekötő esetében egy fontos (és alapszintű) kezelőt kell implementálni OnTake (amely az OData-ban lefordítva $top ), mivel korlátozza a visszaadott sorok számát. A Power Query-élmény mindig sorokat OnTake1000 hajt végre, amikor előnézeteket jelenít meg a kezelőben és a lekérdezésszerkesztőben, így a felhasználók jelentős teljesítménybeli javulást tapasztalhatnak a nagyobb adatkészletek használatakor.