Just want to share experience for version 7.3.
The Retail SDK link: https://docs.microsoft.com/en-us/dynamics365/retail/dev-itpro/retail-sdk/retail-sdk-samples and example in "RetailSDK\Documents\SampleExtensionsInstructions\EmailPreference" were outdated for 7.3 already. Here is the new sample I got from Microsoft support.
Create new [ext] type
CREATE TYPE [ext].[EXTENSIONPROPERTIESTABLETYPECUSTOM] AS TABLE(
[PARENTRECID] [bigint] NOT NULL,
[PROPERTYNAME] [nvarchar](512) NOT NULL,
[PROPERTYVALUE] [nvarchar](512) NULL
)
GO
GRANT EXECUTE ON TYPE::[ext].[EXTENSIONPROPERTIESTABLETYPECUSTOM]
TO [UsersRole] WITH GRANT OPTION;
GO
GRANT EXECUTE ON TYPE::[ext].[EXTENSIONPROPERTIESTABLETYPECUSTOM]
TO [PublishersRole] WITH GRANT OPTION;
GO
GRANT EXECUTE ON TYPE::[ext].[EXTENSIONPROPERTIESTABLETYPECUSTOM]
TO [DeployExtensibilityRole] WITH GRANT OPTION;
GO
Create the extension stored procedure that is used by EXT to update the custom fields.
CREATE PROCEDURE [ext].[UPDATECUSTOMEREXTENSIONPROPERTIES]
@TVP_EXTENSIONPROPERTIESTABLETYPE [ext].[EXTENSIONPROPERTIESTABLETYPECUSTOM] READONLY
AS
BEGIN
SET NOCOUNT ON;
....
END
In CRT, using CustomExtensionPropertiesTableType for the [ext] type.
protected override SingleEntityDataServiceResponse<Customer> Process(CreateOrUpdateCustomerDataRequest request)
{
ThrowIf.Null(request, "request");
using (var databaseContext = new SqlServerDatabaseContext(request))
using (var transactionScope = new TransactionScope())
{
// Execute original functionality to save the customer.
var requestHandler = new Microsoft.Dynamics.Commerce.Runtime.DataServices.SqlServer.CustomerSqlServerDataService();
var response = (SingleEntityDataServiceResponse<Customer>)requestHandler.Execute(request);
// Execute additional functionality to save the customer's extension properties.
if (!request.Customer.ExtensionProperties.IsNullOrEmpty())
{
var countryRegionCodePhone = request.Customer.GetProperty("COUNTRYREGIONCODEPHONE").ToString();
var phone = request.Customer.Phone;
ICollection<CommerceProperty> properties = new List<CommerceProperty>();
properties.Add(new CommerceProperty("COUNTRYREGIONCODEPHONE", countryRegionCodePhone));
// The stored procedure will determine which extension properties are saved to which tables.
ParameterSet parameters = new ParameterSet();
parameters["@TVP_EXTENSIONPROPERTIESTABLETYPE"] = new CustomExtensionPropertiesTableType(
request.Customer.RecordId, properties);
databaseContext.ExecuteStoredProcedureNonQuery("[ext].[UPDATECUSTOMEREXTENSIONPROPERTIES]", parameters);
var context = new RequestContext(request.RequestContext.Runtime);
if (!request.Customer.ExtensionProperties.IsNullOrEmpty())
{
if (phone != null && countryRegionCodePhone != null)
{
var transactionServiceClient = new TransactionServiceClient(context);
ReadOnlyCollection<object> results = transactionServiceClient.InvokeExtensionMethod(
"UpdateCustomerContryCode",
request.Customer.AccountNumber,
request.RequestContext.GetChannelConfiguration().InventLocationDataAreaId,
phone,
countryRegionCodePhone);
bool success = Convert.ToBoolean(results[0]);
if (!success)
{
string error = Convert.ToString(results[1]);
RetailLogger.Log.GenericWarningEvent(string.Format("Failed to update customer phone country code due to error: {0}", error));
throw new CommerceException(error, "Failed to update customer phone country code.");
}
}
}
}
transactionScope.Complete();
return response;
}
}