MarkMpn.Sql4Cds.Engine 5.4.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package MarkMpn.Sql4Cds.Engine --version 5.4.1
NuGet\Install-Package MarkMpn.Sql4Cds.Engine -Version 5.4.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MarkMpn.Sql4Cds.Engine" Version="5.4.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add MarkMpn.Sql4Cds.Engine --version 5.4.1
#r "nuget: MarkMpn.Sql4Cds.Engine, 5.4.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install MarkMpn.Sql4Cds.Engine as a Cake Addin
#addin nuget:?package=MarkMpn.Sql4Cds.Engine&version=5.4.1

// Install MarkMpn.Sql4Cds.Engine as a Cake Tool
#tool nuget:?package=MarkMpn.Sql4Cds.Engine&version=5.4.1

alternate text is missing from this package README image 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 query
  • Connection - the IOrganizationService instance that provides access to this data source
  • Metadata - an IAttributeMetadataCache instance that provides cached access to the metadata for this data source. A standard implementation is provided by AttributeMetadataCache
  • TableSizeCache - an ITableSizeCache instance that provides a quick estimate of the number of records in each table in the data source. A standard implementation is provided by TableSizeCache

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 contain inner and outer 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 FetchXML valueof attribute in filter conditions

  • MaxDegreeOfParallelism - how many requests can be made in parallel? Currently used for DML and partitioned aggregate queries

  • UseTDSEndpoint - indicates if the preview TDS Endpoint should be used where possible to execute SELECT queries

  • PrimaryEndPoint - the name of the DataSource that queries will run against unless the FROM clause explicitly references a different data source

  • UserId - the unique identifier of the current user

  • BlockDeleteWithoutWhere - indicates if an error should be produced if running a DELETE query without a corresponding WHERE clause

  • BlockUpdateWithoutWhere - indicates if an error should be produced if running a UPDATE query without a corresponding WHERE clause

  • Cancelled - set to true to stop further execution of the query

  • UseBulkDelete - set to true to use a bulk delete job instead of deleting individual records for a DELETE query

  • ConfirmDelete() - callback method to allow the application to confirm a DELETE query should go ahead

  • ConfirmInsert() - callback method to allow the application to confirm an INSERT query should go ahead

  • ConfirmUpdate() - callback method to allow the application to confirm an UPDATE query should go ahead

  • ConfinueRetrieval() - callback method to allow the application to stop queries that involve too many data retrieval requests

  • Progress() - callback method to allow the application to log progress from the query

  • RetrievingNextPagE() - 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 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. 
.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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
8.0.0 790 11/25/2023
7.6.1 902 10/16/2023
7.6.0 741 9/30/2023
7.5.2 152 9/17/2023
7.5.1 142 9/11/2023
7.5.0 162 9/4/2023
7.4.0 558 8/7/2023
7.3.0 452 6/12/2023
7.2.2 732 5/2/2023
7.2.1 150 4/30/2023
7.1.0 512 1/31/2023
7.0.3 632 10/11/2022
7.0.2 425 10/2/2022
7.0.1 422 9/28/2022
7.0.0 431 9/21/2022
6.4.0 528 7/28/2022
6.3.0 433 6/28/2022
6.2.1 438 5/26/2022
6.2.0 434 5/18/2022
6.1.0 442 5/11/2022
6.0.1 500 4/13/2022
6.0.0 478 4/10/2022
5.4.1 519 1/18/2022
5.4.0 313 1/4/2022
5.3.1 302 12/2/2021
5.3.0 304 11/27/2021
5.2.5 362 9/29/2021
5.2.4 330 9/16/2021
5.2.3 319 9/1/2021
5.2.2 323 8/31/2021
5.2.1 391 6/29/2021
5.1.1 367 5/15/2021
5.1.0 356 5/6/2021
5.0.0 367 4/29/2021
4.1.0 357 3/18/2021
4.0.3 340 2/20/2021
4.0.2 349 2/10/2021
4.0.1 355 1/28/2021
4.0.0 375 1/13/2021
3.1.0 498 12/13/2020
3.0.0 436 11/2/2020
2.3.0 441 8/28/2020
2.2.0 455 7/15/2020
2.1.0 551 5/24/2020
2.0.1 451 4/23/2020
2.0.0 500 4/17/2020
1.0.7 619 1/31/2020

Improved aggregate results when grouping by lookup columns
Detect use of window functions
Fixed use of DATEPART groupings when using UTC timezone