Class MultiQueryProviderBase
This is the recommended standard base class for MultiQuery providers, i.e., providers that aggregate multiple sub providers into one data stream. It implements the IArchiveMultiQueryProvider interface, and provides its own contract for derived classes.
Inheritance
Implements
Inherited Members
Namespace: SuperOfficeCRMArchiveLists
Assembly: SoDataBase.BusinessLogic.dll
Syntax
public abstract class MultiQueryProviderBase : IArchiveMultiQueryProvider, IArchiveProvider, IArchiveProviderHasRows, IArchiveProviderHasColumns, IArchiveProviderHasEntities
Remarks
The main functionality of this class is twofold. First, it keeps track of multiple sub providers and uses the SuperOffice.CRM.ArchiveLists.MultiQueryProviderBase.EntityHelper to manage the entities offered by these providers (multiple providers may offer the same entity, or different entities). Second, during data reading it starts the sub providers reading in parallell, and then performs the ordered merging of all the sub providers into one data stream according to the current orderby criteria.
Constructors
MultiQueryProviderBase()
Constructor, sets up the instance and column helper
Declaration
protected MultiQueryProviderBase()
MultiQueryProviderBase(Action<ArchiveColumnInfo, ArchiveColumnInfo>, params string[])
Declaration
protected MultiQueryProviderBase(Action<ArchiveColumnInfo, ArchiveColumnInfo> processColumnDuplicates, params string[] subProviderNames)
Parameters
| Type | Name | Description |
|---|---|---|
| ActionArchiveColumnInfoArchiveColumnInfo | processColumnDuplicates | |
| string | subProviderNames |
MultiQueryProviderBase(params string[])
Declaration
protected MultiQueryProviderBase(params string[] subProviderNames)
Parameters
| Type | Name | Description |
|---|---|---|
| string | subProviderNames |
Properties
ColumnHelper
The column helper that accumulates columns from all subproviders, according to the strategy bits
Declaration
protected ColumnHelper ColumnHelper { get; }
Property Value
| Type | Description |
|---|---|
| ColumnHelper |
DebugXML
Declaration
public XmlDocument DebugXML { get; }
Property Value
| Type | Description |
|---|---|
| XmlDocument |
HaveReadToEnd
If all subproviders have been read all the way, then this is set to true
Declaration
protected bool HaveReadToEnd { get; }
Property Value
| Type | Description |
|---|---|
| bool |
InhibitDistinctPrimaryKeys
Override this property and return TRUE if you wish to disable the check for distinct primary keys. This will save some time and space, at the cost of potential duplicate rows that would otherwise have been discarded
Declaration
public virtual bool InhibitDistinctPrimaryKeys { get; }
Property Value
| Type | Description |
|---|---|
| bool |
InhibitParallelStart
If true, subproviders will be started in sequence, rather than in parallel
Declaration
public bool InhibitParallelStart { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
Options
Options, passed in through the GetRows() call
Declaration
protected string Options { get; }
Property Value
| Type | Description |
|---|---|
| string |
OrderBy
Returns the parameter to the latest SetOrderBy call
Declaration
protected ArchiveOrderByInfo[] OrderBy { get; }
Property Value
| Type | Description |
|---|---|
| ArchiveOrderByInfo |
OrderByRequired
Declaration
public bool OrderByRequired { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
OrderByRequiresAll
If this property is true, a column will be offered for OrderBy only if all providers have set it as CanOrderBy. Default is true.
Declaration
public bool OrderByRequiresAll { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
PageNumber
Get the current page number, as ordered by our client
Declaration
protected int PageNumber { get; }
Property Value
| Type | Description |
|---|---|
| int |
PageSize
Get the current page size, as ordered by our client
Declaration
protected int PageSize { get; }
Property Value
| Type | Description |
|---|---|
| int |
Providers
Readonly property that returns the current provider list
Declaration
public List<IArchiveProvider> Providers { get; }
Property Value
| Type | Description |
|---|---|
| ListIArchiveProvider |
RestrictionHelper
The restriction helper that keeps track of restrictions and builds sql (via RestrictionOperations)
Declaration
protected RestrictionHelper RestrictionHelper { get; }
Property Value
| Type | Description |
|---|---|
| RestrictionHelper |
RestrictionRequiresAll
If this property is true, a column will have a restriction type only if all providers have set a restriction type on it, and all providers actually offer it.
Declaration
public bool RestrictionRequiresAll { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
Methods
AcceptRow(ArchiveRow)
This method is called for every row, and provides a way to reject rows from the final result
Declaration
protected virtual bool AcceptRow(ArchiveRow row)
Parameters
| Type | Name | Description |
|---|---|---|
| ArchiveRow | row | Row to be evaluated |
Returns
| Type | Description |
|---|---|
| bool | true if the row is to be accepted |
AddSubProvider<ProviderType>(ProviderType)
Add one provider to this multi query provider
Declaration
public ProviderType AddSubProvider<ProviderType>(ProviderType subProvider) where ProviderType : IArchiveProvider
Parameters
| Type | Name | Description |
|---|---|---|
| ProviderType | subProvider | Provider to be added |
Returns
| Type | Description |
|---|---|
| ProviderType |
Type Parameters
| Name | Description |
|---|---|
| ProviderType | Type of provider, inferred from parameter |
Remarks
The generic input and return types are there so that you can write code like the following:
SomeProvider provider = AddSubProvider( new SomeProvider() );
That is, the provider you add is considered simply as an IArchiveProvider (see the where clause of the declaration), but it is returned as the actual type you sent in, whatever that might be - so it can be assigned to a strongly typed member. This saves a line, as you would otherwise have to assign the newly created subprovider, and then add it. A small convenience...
Close()
Call this method after the last desired row has been read; this gives the provider the chance to close and free any underlying queries. This will be propagated to all subproviders.
Declaration
public virtual void Close()
CreateAndAddProvidersAsync(AddProviderInfo[])
Declaration
protected Task CreateAndAddProvidersAsync(MultiQueryProviderBase.AddProviderInfo[] providers)
Parameters
| Type | Name | Description |
|---|---|---|
| AddProviderInfo | providers |
Returns
| Type | Description |
|---|---|
| Task |
GetAvailableColumns()
Get the list of available columns. This is a set union of all columns provided by all sub providers
Declaration
public virtual List<ArchiveColumnInfo> GetAvailableColumns()
Returns
| Type | Description |
|---|---|
| ListArchiveColumnInfo | List of available columns |
GetAvailableEntities()
Get the available entities. This is the set union of all entities offered by all sub providers
Declaration
public virtual List<ArchiveRowTypeInfo> GetAvailableEntities()
Returns
| Type | Description |
|---|---|
| ListArchiveRowTypeInfo | List of entities |
GetFinalRowCount()
Actual number of rows in query, valid only when HaveReadToEnd = true; otherwise you get -1
Declaration
protected int GetFinalRowCount()
Returns
| Type | Description |
|---|---|
| int |
GetReaderAsync(string, CancellationToken)
Start the reader and return an IDataReader (which, as we remember, also inherits IDataRecord for access to individual data fields). This provides an alternative, more generic and more standards-based interface to data. Use either GetRows or GetReader on any particular archive provider instance.
Declaration
public virtual Task<DbDataReader> GetReaderAsync(string options, CancellationToken cancellationToken = default)
Parameters
| Type | Name | Description |
|---|---|---|
| string | options | |
| CancellationToken | cancellationToken |
Returns
| Type | Description |
|---|---|
| TaskDbDataReader |
GetResultInformationAsync()
Get additional information about the result, such as row count or other optional items. This method should be called some time after GetRows, but before Close. Delaying calls to this method as long as possible will give its (asynchronous) internal counterpart more time to complete and lessen the response-time impact of calling it.
Declaration
public Task<ArchiveResultInformation> GetResultInformationAsync()
Returns
| Type | Description |
|---|---|
| TaskArchiveResultInformation |
GetRowsAsync(string, CancellationToken)
Get the result enumerator. Accessing this enumerator will cause all sub query providers to be initialized in parallell (subject to global thread limits), rows will be skipped according to the current page settings, and results will come in the order specified by the current order by settings. Restrictions, desired columns, entities etc must be set before accessing this property.
Declaration
public virtual IAsyncEnumerable<ArchiveRow> GetRowsAsync(string options, CancellationToken cancellationToken = default)
Parameters
| Type | Name | Description |
|---|---|---|
| string | options | |
| CancellationToken | cancellationToken |
Returns
| Type | Description |
|---|---|
| IAsyncEnumerableArchiveRow |
InnerPopulateRow(ArchiveRow)
This virtual method is called after a row has been selected as being the 'next' to be returned by this multi query provider, and provides an opportunity to modify it before it is returned to the client.
Declaration
protected virtual void InnerPopulateRow(ArchiveRow row)
Parameters
| Type | Name | Description |
|---|---|---|
| ArchiveRow | row | Row being processed, may be modified (with due care) |
PreGetRows()
Hook for subclasses that wish to perform custom processing right before the GetRows call is executed
Declaration
protected virtual void PreGetRows()
RemoveSubProvider<ProviderType>(ProviderType)
Declaration
protected ProviderType RemoveSubProvider<ProviderType>(ProviderType subProvider) where ProviderType : IArchiveProvider
Parameters
| Type | Name | Description |
|---|---|---|
| ProviderType | subProvider |
Returns
| Type | Description |
|---|---|
| ProviderType |
Type Parameters
| Name | Description |
|---|---|
| ProviderType |
SetDesiredColumns(params string[])
Set the desired columns. This information is simply propagated to all sub providers. If rows are fetched from providers that do not have a value for any particular column, the ColumnData member of the ArchiveRow structure will be null in that row/column
Declaration
public virtual void SetDesiredColumns(params string[] columnIds)
Parameters
| Type | Name | Description |
|---|---|---|
| string | columnIds | Array of column ids as strings |
SetDesiredEntities(params string[])
Set desired entities. This information is propagated to all sub providers, and saved internally.
Declaration
public virtual void SetDesiredEntities(params string[] entities)
Parameters
| Type | Name | Description |
|---|---|---|
| string | entities |
SetOrderBy(ArchiveOrderByInfo[])
Set the order by specification. This information is propagated to each sub provider, and used internally during the data stream merge
Declaration
public virtual void SetOrderBy(ArchiveOrderByInfo[] orderBy)
Parameters
| Type | Name | Description |
|---|---|---|
| ArchiveOrderByInfo | orderBy | Array of order by specifications |
SetPagingInfo(int, int)
Set paging information for the provider.
Declaration
public virtual void SetPagingInfo(int pageSize, int pageNumber)
Parameters
| Type | Name | Description |
|---|---|---|
| int | pageSize | Size of page |
| int | pageNumber | Zero-based page number |
Remarks
If there are multiple sub-providers, each needs to return a sufficient number of rows to supply the actual desired page on its own, just in case the sorting makes it the one to come up top all the time. Here we just remember the settings; the actual delegation is done in MultiProviderMerge where we know how many active subproviders there are.
SetRestriction(ArchiveRestrictionInfo[])
Set the restriction for the provider. The restriction is simply propagated to all sub providers.
Declaration
public virtual bool SetRestriction(ArchiveRestrictionInfo[] restrictions)
Parameters
| Type | Name | Description |
|---|---|---|
| ArchiveRestrictionInfo | restrictions | Array of restrictions |
Returns
| Type | Description |
|---|---|
| bool |
SetRestrictionAndDropUnrestrictedProviders(ArchiveRestrictionInfo[])
Propagate restrictions to all subproviders, and then drop any of them that did not process any restriction.
Declaration
public bool SetRestrictionAndDropUnrestrictedProviders(ArchiveRestrictionInfo[] restrictions)
Parameters
| Type | Name | Description |
|---|---|---|
| ArchiveRestrictionInfo | restrictions |
Returns
| Type | Description |
|---|---|
| bool |
Remarks
Ths behaviour is useful in situations where you want to offer many different 'channels' of data, but do not want to run them unrestricted. Here, any provider that does not understand at least one of the given restrictions is dropped.