Below are some code samples for reading and writing data in Channel database. This is just for Channel database. This does not necessary mean that the data needs to go to D365 HQ. It may, either via CDX pull job or via Real-time service call. This information is only for simple reads and writes in Channel db.
Prerequisites:
Dynamics 365 for Operations (1611)
KB3214687
KB3214679
First, create the SQL table in ax schema and a view in crt schema:
CREATE TABLE [ax].[MY_EXTENSION]( [DATAAREAID] [nvarchar](4) NOT NULL, [RECID] [bigint] NOT NULL, [COL1] [int] NOT NULL, [COL2] [nvarchar](100) NOT NULL, [COL3] [bit] NOT NULL, [ACCOUNTNUM] [nvarchar](20) NOT NULL) . . . END GO CREATE VIEW [crt].[MY_EXTENSIONVIEW] AS ( SELECT ACCOUNTNUM, DATAAREAID, COL1, COL2, COL3 FROM [ax].[MY_EXTENSION] ) GO GRANT SELECT ON [crt].[MY_EXTENSIONVIEW] TO [UsersRole]; GO
The shown sample adds 3 columns to be stored from 3 extension properties.
Grant the right permissions to table and view. This is the list of supported SQL roles:
DataSyncUsersRole | Used by CDX process account |
PublishersRole | Used by publishing process account (eCommerce) |
ReportUsersRole | Used by reporting user account |
UsersRole | Used by runtime user (RetailServer) |
Next, create a sproc for updating:
CREATE PROCEDURE [crt].[MY_UPDATEEXTENSIONPROPERTIES] @TVP_EXTENSIONPROPERTIESTABLETYPE [crt].EXTENSIONPROPERTIESTABLETYPE READONLY AS BEGIN DECLARE @nvc_DataAreaId NVARCHAR(4); DECLARE @recId bigint; DECLARE @accountNum [nvarchar](20); DECLARE @Col1Value int = 0; DECLARE @Col2Value nvarchar(100) = ''; DECLARE @Col3Value bit = 0; SELECT DISTINCT TOP 1 @recId = tp.PARENTRECID, @nvc_DataAreaId = ct.DATAAREAID, @accountNum = ct.ACCOUNTNUM FROM @TVP_EXTENSIONPROPERTIESTABLETYPE tp JOIN [ax].CUSTTABLE ct on ct.RECID = tp.PARENTRECID WHERE tp.PARENTRECID <> 0 SELECT @Col1Value = COALESCE(tp.PROPERTYVALUE, 0) FROM @TVP_EXTENSIONPROPERTIESTABLETYPE tp where tp.PARENTRECID <> 0 and tp.PROPERTYNAME = 'COL1' SELECT @Col2Value = COALESCE(tp.PROPERTYVALUE, '') FROM @TVP_EXTENSIONPROPERTIESTABLETYPE tp where tp.PARENTRECID <> 0 and tp.PROPERTYNAME = 'COL2' SELECT @Col3Value = CAST(CASE WHEN tp.PROPERTYVALUE = 'True' THEN 1 ELSE 0 END AS BIT) FROM @TVP_EXTENSIONPROPERTIESTABLETYPE tp where tp.PARENTRECID <> 0 and tp.PROPERTYNAME = 'COL3' MERGE INTO [ax].[MY_CUSTOMEREXTENSION] dest USING (SELECT @accountNum as ACCOUNTNUM) as source on dest.ACCOUNTNUM = source.ACCOUNTNUM WHEN matched then update set dest.COL1 = @Col1Value, dest.COL2 = @Col2Value, dest.COL3 = @Col3Value when not matched then INSERT (RECID, ACCOUNTNUM, DATAAREAID, COL1, COL2, COL3) VALUES (@recId, @accountNum, @nvc_DataAreaId, @Col1Value, @Col2Value, @Col3Value); END GO GRANT EXECUTE ON [crt].[MY_UPDATECUSTOMEREXTENSIONPROPERTIES] TO [UsersRole]; GO
Note the MERGE INTO statement. This allows to either create or update a record.
For reading in the CRT, here especially for extension properties, use SQLPagedQuery, SQLServerDatabaseContext and ExtensionsEntity:
var query = new SqlPagedQuery(QueryResultSettings.SingleRecord) { Select = new ColumnSet(new string[] { "COL1", "COL2", "COL3" }), From = "MY_EXTENSIONVIEW", Where = "ACCOUNTNUM = @accountNum AND DATAAREAID = @dataAreaId", }; query.Parameters["@accountNum"] = customer.AccountNumber; query.Parameters["@dataAreaId"] = request.RequestContext.GetChannelConfiguration().InventLocationDataAreaId; using (var databaseContext = new SqlServerDatabaseContext(request)) { ExtensionsEntity extensions = databaseContext.ReadEntity(query).FirstOrDefault(); if (extensions != null) { var col1 = extensions.GetProperty("COL1"); if (col1 != null) { customer.SetProperty("COL1", col1); } else { customer.SetProperty("COL1", 0); } . . . } else { customer.SetProperty("COL1", 0); } }
In order to write the data to the db, use this code to call the sproc shown above:
using (var databaseContext = new SqlServerDatabaseContext(r)) using (var transactionScope = new TransactionScope()) { if (!r.Customer.ExtensionProperties.IsNullOrEmpty()) { ParameterSet parameters = new ParameterSet(); parameters["@TVP_EXTENSIONPROPERTIESTABLETYPE"] = new ExtensionPropertiesTableType(r.Customer.RecordId, r.Customer.ExtensionProperties).DataTable; databaseContext.ExecuteStoredProcedureNonQuery("MY_UPDATEEXTENSIONPROPERTIES", parameters); } transactionScope.Complete(); }
In the case of you want to write other data to the database (no extension properties to entities), build the SqlParameters one by one and match in your sproc. For reading, it may be easier to just treat it as extension properties, then convert to whatever you want. Or you could create your own entity and query for that.