/// <summary> /// Base DbConnection (SqlConnection) extension for Offset Paginated Batch Query capability. /// /// Public Facade method to provide dynamically paginated results using Offset based paging/slicing. /// /// NOTE: Since RepoDb supports only Batch querying using Page Number and Page Size -- it's less flexible /// than pure Offset based paging which uses Skip/Take. Therefore, this logic provides an extension /// of RepoDb core functionality; and if this is ever provided by the Core functionality /// this facade will remain as a proxy to the core feature. /// /// NOTE: Cursor Slice Querying is more flexible and works perfectly for Offset Based processing also so this /// represents a facade around the Cursor Page slicing that maps between Skip/Take and Cursor paging paradigm. /// /// NOTE: If the implementor needs further optimization then it's recommended to implement the optimized query /// exactly as required; this should work well for many common use cases. /// /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="dbConnection">Extends the RepoDb BaseRepository abstraction</param> /// <param name="orderBy"></param> /// <param name="whereRawSql"></param> /// <param name="pagingParams"></param> /// <param name="tableName"></param> /// <param name="hints"></param> /// <param name="fields"></param> /// <param name="commandTimeout"></param> /// <param name="transaction"></param> /// <param name="logTrace"></param> /// <param name="cancellationToken"></param> /// <returns>OffsetPageResults<TEntity></returns> public static async Task <OffsetPageResults <TEntity> > GraphQLBatchSkipTakeQueryAsync <TEntity>( this DbConnection dbConnection, IEnumerable <OrderField> orderBy, RawSqlWhere whereRawSql = null, //NOTE: This Overload allows cases where NO WHERE Filter is needed... IRepoDbOffsetPagingParams pagingParams = default, string tableName = null, string hints = null, IEnumerable <Field> fields = null, int?commandTimeout = null, IDbTransaction transaction = null, Action <string> logTrace = null, CancellationToken cancellationToken = default ) //ALL entities retrieved and Mapped for Cursor Pagination must support IHaveCursor interface. where TEntity : class { //Slice Querying is more flexible and works perfectly for Offset Based processing also so there is no // need to maintain duplicated code for the less flexible paging approach since we can provide // the simplified Offset Paging facade on top of the existing Slice Queries! var sliceResults = await dbConnection.GraphQLBatchSliceQueryAsync <TEntity>( orderBy : orderBy, whereRawSql : whereRawSql, pagingParams : ConvertOffsetParamsToCursorParams(pagingParams), tableName : tableName, hints : hints, fields : fields, commandTimeout : commandTimeout, transaction : transaction, logTrace : logTrace, cancellationToken : cancellationToken ).ConfigureAwait(false); //Map the Slice into the OffsetPageResults for simplified processing by calling code... return(sliceResults.ToOffsetPageResults());; }
private static IRepoDbCursorPagingParams ConvertOffsetParamsToCursorParams(IRepoDbOffsetPagingParams offsetParams) { return(new RepoDbCursorPagingParams( after: offsetParams?.Skip, first: offsetParams?.Take, isTotalCountRequested: offsetParams?.IsTotalCountRequested ?? false )); }
public async Task <IOffsetPageResults <ICharacter> > GetOffsetPagedCharactersAsync( IEnumerable <Field> selectFields, IEnumerable <OrderField> sortFields, IRepoDbOffsetPagingParams pagingParams ) { await using var sqlConn = CreateConnection(); var offsetPageResults = await sqlConn.GraphQLBatchSkipTakeQueryAsync <CharacterDbModel>( pagingParams : pagingParams, orderBy : sortFields ?? DefaultCharacterSortFields, fields : selectFields ); var convertedPage = offsetPageResults.AsMappedType(r => MapDbModelToCharacterModel(r)); return(convertedPage); }
/// <summary> /// Base Repository extension for Offset Paginated Batch Query capability. /// /// Public Facade method to provide dynamically paginated results using Offset based paging/slicing. /// /// NOTE: Since RepoDb supports only Batch querying using Page Number and Page Size -- it's less flexible /// than pure Offset based paging which uses Skip/Take. Therefore, this logic provides an extension /// of RepoDb core functionality; and if this is ever provided by the Core functionality /// this facade will remain as a proxy to the core feature. /// /// NOTE: Cursor Slice Querying is more flexible and works perfectly for Offset Based processing also so this /// represents a facade around the Cursor Page slicing that maps between Skip/Take and Cursor paging paradigm. /// /// NOTE: If the implementor needs further optimization then it's recommended to implement the optimized query /// exactly as required; this should work well for many common use cases. /// /// </summary> /// <typeparam name="TEntity"></typeparam> /// <typeparam name="TDbConnection"></typeparam> /// <param name="baseRepo">Extends the RepoDb BaseRepository abstraction</param> /// <param name="orderBy"></param> /// <param name="whereExpression"></param> /// <param name="pagingParams"></param> /// <param name="tableName"></param> /// <param name="hints"></param> /// <param name="fields"></param> /// <param name="commandTimeout"></param> /// <param name="transaction"></param> /// <param name="logTrace"></param> /// <param name="cancellationToken"></param> /// <returns>OffsetPageResults<TEntity></returns> public static async Task <OffsetPageResults <TEntity> > GraphQLBatchSkipTakeQueryAsync <TEntity, TDbConnection>( this BaseRepository <TEntity, TDbConnection> baseRepo, IEnumerable <OrderField> orderBy, //NOTE: Expression is required to prevent Ambiguous Signatures Expression <Func <TEntity, bool> > whereExpression, IRepoDbOffsetPagingParams pagingParams = default, string tableName = null, string hints = null, IEnumerable <Field> fields = null, int?commandTimeout = null, IDbTransaction transaction = null, Action <string> logTrace = null, CancellationToken cancellationToken = default ) //ALL entities retrieved and Mapped for Cursor Pagination must support IHaveCursor interface. where TEntity : class where TDbConnection : DbConnection, new() { //Slice Querying is more flexible and works perfectly for Offset Based processing also so there is no // need to maintain duplicated code for the less flexible paging approach since we can provide // the simplified Offset Paging facade on top of the existing Slice Queries! var sliceResults = await baseRepo.GraphQLBatchSliceQueryAsync <TEntity, TDbConnection>( orderBy : orderBy, whereExpression : whereExpression, pagingParams : ConvertOffsetParamsToCursorParams(pagingParams), tableName : tableName, hints : hints, fields : fields, commandTimeout : commandTimeout, transaction : transaction, logTrace : logTrace, cancellationToken : cancellationToken ).ConfigureAwait(false); //Map the Slice into the OffsetPageResults for simplified processing by calling code... return(sliceResults.ToOffsetPageResults()); }