MarkMpn.Sql4Cds.Engine
5.4.0
See the version list below for details.
dotnet add package MarkMpn.Sql4Cds.Engine --version 5.4.0
NuGet\Install-Package MarkMpn.Sql4Cds.Engine -Version 5.4.0
<PackageReference Include="MarkMpn.Sql4Cds.Engine" Version="5.4.0" />
paket add MarkMpn.Sql4Cds.Engine --version 5.4.0
#r "nuget: MarkMpn.Sql4Cds.Engine, 5.4.0"
// Install MarkMpn.Sql4Cds.Engine as a Cake Addin #addin nuget:?package=MarkMpn.Sql4Cds.Engine&version=5.4.0 // Install MarkMpn.Sql4Cds.Engine as a Cake Tool #tool nuget:?package=MarkMpn.Sql4Cds.Engine&version=5.4.0
SQL 4 CDS
By Mark Carrington, supported by Data8
SQL 4 CDS provides an engine and XrmToolBox tool for using standard SQL syntax to query data stored in Microsoft Dataverse / Dynamics 365.
It converts the provided SQL query into the corresponding FetchXML syntax and allows the associated query to be executed, including the following types of query:
SELECT
INSERT
UPDATE
DELETE
For example:
-- Get contact details
SELECT c.firstname,
c.lastname,
a.telephone1
FROM contact AS c
INNER JOIN account AS a
ON c.parentcustomerid = a.accountid
WHERE c.firstname = 'Mark' AND
a.statecode = 0
ORDER BY c.createdon DESC
-- Deactivate contacts without an email address
UPDATE contact
SET statecode = 1, statuscode = 2
WHERE emailaddress1 IS NULL
The engine converts all the SQL syntax that has a direct equivalent in FetchXML. It also attempts to support some more SQL features
that do not have an equivalent in FetchXML, such as calculated fields, HAVING
clauses and more.
When executing a query it will take into account specific Dataverse features to improve the performance or results compared to simply executing the FetchXML directly, e.g.:
- Faster
SELECT count(*) FROM entity
query execution using RetrieveTotalRecordCountRequest - Automatically retrieving multiple pages of large result sets
- Work around
AggregateQueryRecordLimit
errors by retrieving all the individual records and applying the aggregation in-memory.
As well as querying data with FetchXML, SQL 4 CDS can also query metadata by translating the SQL query into a RetrieveMetadataChangesRequest or RetrieveAllOptionSetsRequest:
-- Find attributes without a description
SELECT entity.logicalname,
attribute.logicalname
FROM metadata.entity
INNER JOIN metadata.attribute
ON entity.logicalname = attribute.entitylogicalname
WHERE attribute.description IS NULL
FetchXML Builder Integration
As well as writing and executing queries as SQL, the generated FetchXML can be sent to FetchXML Builder for further editing or converting to another syntax such as OData. You can also start building a query in FetchXML Builder and then edit it in SQL 4 CDS.
Library Usage
The NuGet package includes assemblies for .NET Framework 4.6.2 and later, and .NET Core 3.1 and later.
The main entry point to the library is the ExecutionPlanBuilder
class. This exposes a Build()
method
that accepts a SQL string and produces a set of execution plan nodes that the calling application can execute.
The ExecutionPlanBuilder
class requires details of the data sources (D365 instances) the query will be executed
against, and a set of options that control how the SQL query will be converted and executed.
The DataSource
class has the following properties:
Name
- the name this data source can be referred to by in the SQL queryConnection
- theIOrganizationService
instance that provides access to this data sourceMetadata
- anIAttributeMetadataCache
instance that provides cached access to the metadata for this data source. A standard implementation is provided byAttributeMetadataCache
TableSizeCache
- anITableSizeCache
instance that provides a quick estimate of the number of records in each table in the data source. A standard implementation is provided byTableSizeCache
The calling application must also provide an implementation of the IQueryExecutionOptions
interface. This provides
various properties and methods that can control how the query is converted and executed:
BatchSize
- when executing DML operations, how many requests should be sent to the server at once?BypassCustomPlugins
- when executing DML operations, should custom plugins be bypassed?JoinOperatorsAvailable
- depending on the version of D365, different join operators are available. This property lists the operators that are available for SQL 4 CDS to use. This should containinner
andouter
at a minimum.UseLocalTimeZone
- when working with date values, this property indicates whether the local or UTC time zone should be used.ColumnComparisonAvailable
- indicates whether the version of D365 that will be executing the query supports the FetchXMLvalueof
attribute in filter conditionsMaxDegreeOfParallelism
- when executing DML operations, how many requests can be made in parallel?UseTDSEndpoint
- indicates if the preview TDS Endpoint should be used where possible to execute SELECT queriesPrimaryEndPoint
- the name of theDataSource
that queries will run against unless the FROM clause explicitly references a different data sourceUserId
- the unique identifier of the current userBlockDeleteWithoutWhere
- indicates if an error should be produced if running a DELETE query without a corresponding WHERE clauseBlockUpdateWithoutWhere
- indicates if an error should be produced if running a UPDATE query without a corresponding WHERE clauseCancelled
- set totrue
to stop further execution of the queryUseBulkDelete
- set totrue
to use a bulk delete job instead of deleting individual records for a DELETE queryConfirmDelete()
- callback method to allow the application to confirm a DELETE query should go aheadConfirmInsert()
- callback method to allow the application to confirm an INSERT query should go aheadConfirmUpdate()
- callback method to allow the application to confirm an UPDATE query should go aheadConfinueRetrieval()
- callback method to allow the application to stop queries that involve too many data retrieval requestsProgress()
- callback method to allow the application to log progress from the queryRetrievingNextPagE()
- callback method to notify the application that the query is retrieving another page of data from the server
Once these pieces are in place, the application can execute a query using code such as:
var svc = new CrmServiceClient("connectionstring");
var metadata = new AttributeMetadataCache(svc);
var dataSource = new DataSource
{
Name = "prod",
Connection = svc,
Metadata = metadata
TableSizeCache = new TableSizeCache(svc, metadata)
};
var dataSources = new Dictionary<string, DataSource>
{
[dataSource.Name] = dataSource
};
var executionPlanBuilder = new ExecutionPlanBuilder(dataSources.Values, options);
var queries = executionPlanBuilder.Build(sql);
foreach (var query in queries)
{
if (query is IDataSetExecutionPlanNode selectQuery)
{
var results = selectQuery.Execute(dataSources, options, null, null);
// results is a DataTable
// Display/save/process the results as required
}
else if (query is IDmlQueryExecutionPlanNode dmlQuery)
{
var message = dmlQuery.Execute(dataSources, options, null, null);
// message is a description of the affect of executing the INSERT/UPDATE/DELETE query
// Display/log it as required
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
.NET Core | netcoreapp3.1 is compatible. |
.NET Framework | net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
-
.NETCoreApp 3.1
- Microsoft.PowerPlatform.Dataverse.Client (>= 0.5.10)
- Microsoft.SqlServer.TransactSql.ScriptDom (>= 150.4897.1)
- System.Data.SqlClient (>= 4.8.3)
-
.NETFramework 4.6.2
- Microsoft.CrmSdk.CoreAssemblies (>= 9.0.2.33)
- Microsoft.CrmSdk.XrmTooling.CoreAssembly (>= 9.1.0.79)
- Microsoft.SqlServer.TransactSql.ScriptDom (>= 150.4897.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
9.5.1 | 906 | 12/12/2024 |
9.5.0 | 268 | 12/10/2024 |
9.4.1 | 1,071 | 11/10/2024 |
9.4.0 | 120 | 11/5/2024 |
9.3.0 | 1,039 | 8/27/2024 |
9.2.0 | 798 | 7/12/2024 |
9.1.0 | 1,091 | 6/10/2024 |
9.0.1 | 869 | 5/8/2024 |
9.0.0 | 152 | 5/2/2024 |
8.0.0 | 2,188 | 11/25/2023 |
7.6.1 | 1,812 | 10/16/2023 |
7.6.0 | 1,513 | 9/30/2023 |
7.5.2 | 194 | 9/17/2023 |
7.5.1 | 176 | 9/11/2023 |
7.5.0 | 201 | 9/4/2023 |
7.4.0 | 599 | 8/7/2023 |
7.3.0 | 502 | 6/12/2023 |
7.2.2 | 839 | 5/2/2023 |
7.2.1 | 186 | 4/30/2023 |
7.1.0 | 2,423 | 1/31/2023 |
7.0.3 | 665 | 10/11/2022 |
7.0.2 | 462 | 10/2/2022 |
7.0.1 | 461 | 9/28/2022 |
7.0.0 | 467 | 9/21/2022 |
6.4.0 | 568 | 7/28/2022 |
6.3.0 | 473 | 6/28/2022 |
6.2.1 | 475 | 5/26/2022 |
6.2.0 | 474 | 5/18/2022 |
6.1.0 | 477 | 5/11/2022 |
6.0.1 | 546 | 4/13/2022 |
6.0.0 | 513 | 4/10/2022 |
5.4.1 | 577 | 1/18/2022 |
5.4.0 | 354 | 1/4/2022 |
5.3.1 | 340 | 12/2/2021 |
5.3.0 | 346 | 11/27/2021 |
5.2.5 | 390 | 9/29/2021 |
5.2.4 | 355 | 9/16/2021 |
5.2.3 | 357 | 9/1/2021 |
5.2.2 | 359 | 8/31/2021 |
5.2.1 | 435 | 6/29/2021 |
5.1.1 | 404 | 5/15/2021 |
5.1.0 | 394 | 5/6/2021 |
5.0.0 | 405 | 4/29/2021 |
4.1.0 | 396 | 3/18/2021 |
4.0.3 | 377 | 2/20/2021 |
4.0.2 | 387 | 2/10/2021 |
4.0.1 | 394 | 1/28/2021 |
4.0.0 | 414 | 1/13/2021 |
3.1.0 | 538 | 12/13/2020 |
3.0.0 | 476 | 11/2/2020 |
2.3.0 | 483 | 8/28/2020 |
2.2.0 | 487 | 7/15/2020 |
2.1.0 | 590 | 5/24/2020 |
2.0.1 | 495 | 4/23/2020 |
2.0.0 | 541 | 4/17/2020 |
1.0.7 | 663 | 1/31/2020 |
Added .NET Core version
Improved aggregate performance with automatic partitioning
Reduced attributes retrieved to process COUNT(*) queries
Fixed GROUP BY and aggregates on virtual attributes
Fixed retrieving file attributes
Fixed GROUP BY and ORDER BY on multi-select picklist fields
Fixed errors when using LIKE queries on non-string fields
Fixed errors when using filters on party list fields
Fixed running queries with more than 10 joins
Fixed DISTINCT with repeated attributes
Fixed use of non-FetchXML functions in WHERE clause
Fixed use of query derived tables with aggregates