Hi!
I'm using the Dynamics CRM's ServiceContext for some time now, because it is so convenient when you have a big tree of entities which you want to create (or update), especially with relationships inbetween them.
But after creating a unique key constraint (using an alternate key on the emailaddress1 field of the Contact entity), I sometimes get strange exceptions when calling the SaveChanges() method.
I call it strange, because when I check the SaveChangesResult's Result property which gets returned, I see a couple of entities in it (7-10 or something, but not the whole list of entities, which is ok, because it uses some sort of partitioning, according to Fiddler output), and the one that has an Error containing the:
A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
message, is a new_relationship entity. It is a custom entity, which has 3 text fields, and a lookup to a contact:
The contact entity inside of it has an EntityState of Changed, because we use duplicate detection to find it in the CRM, and changed some of it's values. It also has the real CRM guid as it's id.
For some reason, it seems to me, that at the backend it wants to create the contact entity again, even though it has a state of Changed.
Which makes it more weird to me, is that sometimes it succeeds when I try to debug it locally, and calling ServiceContext.SaveChanges() from there (but sometimes don't).
We are importing invoices btw, we use our custom new_invoice entity for that, and for an invoice we can get like 90-120 different related entities (contacts, accounts, line_items, taxes, parts, general_items, etc). On some of them, especially on the contact and account we use our own duplicate detection logic (VAT, email, etc), to update the duplicates only and not to re-create them.
I like working with the ServiceContext because it is so easy to create entities with relationships even when the given entities are not existing yet. For example:
var inv_rel = new new_invoice_relationship
{
new_desc = customer_or_company.relationship.desc,
new_type = customer_or_company.relationship.type.ToString(),
new_invoice_new_invoice_relationship = invoice,
account_new_invoice_relationship = account
};
ServiceContext.AddObject(inv_rel);
Here, the account lookup can be a new account, with EntityState = null, or if it was found in the CRM, it has EntityState = Changed.
(Oh, and please don't get confused by the namings here, I purposely chose the new_relationship entity, which is (by the looks of it) throwing the exception for some reason, and which only describes how the current invoice entity is related to the given customer.)
Using fiddler I can see that SaveChanges() sends multiple commands to the Organization service:
I attach the latest request, and response xml from fiddler, maybe you can see something in it.
Request xml (the Execute part only):
Target
new_desc
new_type
INV
new_invoice_relationshipid
a27aa3d4-863f-ea11-84cb-b4692153b9fb
Created
a27aa3d4-863f-ea11-84cb-b4692153b9fb
new_invoice_relationship
new_invoice_new_invoice_relationship
new_name
Invoice - ********/2020
new_date
2020-01-21T00:00:00
new_number
***************
new_po_no
new_currency
HUF
new_document_type
DEL
new_total
44242.36
new_dealer_warehouse
new_xml_file_name
***********************
new_fix_classification_relationship_added
true
new_added_to_multilookup
true
new_invoiceid
987aa3d4-863f-ea11-84cb-b4692153b9fb
Unchanged
987aa3d4-863f-ea11-84cb-b4692153b9fb
new_invoice
new_invoice
false
0
false
contact_new_invoice_relationship
customertypecode
1
new_mobilephone_original
***********
mobilephone
***********
merged
false
new_donotphonehome
true
gendercode
2
new_language_code
*****
territorycode
1
emailaddress1
******@******.com
haschildrencode
1
preferredappointmenttimecode
1
new_record_shared
true
isbackofficecustomer
false
new_datacleanstatus
100000001
msdyn_orgchangestatus
0
owninguser
c23043eb-1466-4012-9781-6ce5675dc173
systemuser
address1_composite
*********
*****
***
lastname
*******
donotpostalmail
false
marketingonly
false
donotphone
false
preferredcontactmethodcode
1
educationcode
1
ownerid
c23043eb-1466-4012-9781-6ce5675dc173
systemuser
crm admin
customersizecode
1
firstname
***********
yomifullname
***********
address2_addresstypecode
1
address1_line1
************
donotemail
true
address2_shippingmethodcode
1
fullname
***************
address1_addressid
123c94b9-bf39-4f63-be6d-15d70f21e607
msdyn_gdproptout
false
address2_freighttermscode
1
statuscode
1
createdon
2019-02-19T21:46:46Z
new_parent_id
*********
new_preferred_dealer
*********
business2
*********
donotsendmm
false
donotfax
false
new_share_record
true
leadsourcecode
1
address1_country
*********
followemail
true
modifiedon
2020-01-24T13:27:23Z
creditonhold
false
address3_addressid
c053e4b8-48eb-4f47-8b61-107f87dd1635
donotbulkemail
false
modifiedby
c23043eb-1466-4012-9781-6ce5675dc173
systemuser
crm admin
new_donotphonebusinness
true
shippingmethodcode
1
createdby
c23043eb-1466-4012-9781-6ce5675dc173
systemuser
crm admin
new_donotphonesms
true
address1_city
***********
donotbulkpostalmail
false
contactid
4f0ea3d9-8f34-e911-867a-0003ff4c4e0b
new_datacleansingscript
true
participatesinworkflow
false
statecode
0
owningbusinessunit
7d6baed2-851b-e911-a960-000d3a29f363
businessunit
new_cust_id
************
address2_addressid
6e5b561d-7c82-41af-87cf-4ab680cfcc43
address1_postalcode
***********
new_business2_original
***********
telephone1
***********
new_phone_businness_opt_in_date_time
2018-12-10T00:00:00
new_donotphonebusinness_scope
A
new_email_opt_in_date_time
2018-12-10T00:00:00
new_donotemail_scope
A
new_phone_home_opt_in_date_time
2018-12-10T00:00:00
new_donotphonehome_scope
A
new_phone_opt_in_date_time
2018-12-10T00:00:00
new_donotphone_scope
A
new_sms_opt_in_date_time
2018-12-10T00:00:00
new_donotphonesms_scope
A
new_fax_opt_in_date_time
2018-12-10T00:00:00
new_donotfax_scope
A
new_postal_mail_opt_in_date_time
2018-12-10T00:00:00
new_donotpostalmail_scope
A
new_donotsharedata
true
new_data_forwarding_opt_in_date_time
2018-12-10T00:00:00
new_donotsharedata_scope
A
Changed
customertypecode
Default Value
merged
No
new_donotphonehome
Allow
gendercode
Female
territorycode
Default Value
haschildrencode
Default Value
preferredappointmenttimecode
Morning
new_record_shared
True
isbackofficecustomer
No
new_datacleanstatus
Clean
msdyn_orgchangestatus
No Feedback
donotpostalmail
Allow
marketingonly
No
donotphone
Allow
preferredcontactmethodcode
Any
educationcode
Default Value
ownerid
crm admin
customersizecode
Default Value
address2_addresstypecode
Default Value
donotemail
Allow
address2_shippingmethodcode
Default Value
msdyn_gdproptout
No
address2_freighttermscode
Default Value
statuscode
Active
createdon
2/19/2019 9:46 PM
new_parent_id
*******
donotsendmm
Do Not Send
donotfax
Do Not Allow
new_share_record
True
leadsourcecode
Default Value
followemail
Allow
modifiedon
1/24/2020 1:27 PM
creditonhold
No
donotbulkemail
Do Not Allow
modifiedby
crm admin
new_donotphonebusinness
Allow
shippingmethodcode
Default Value
createdby
crm admin
new_donotphonesms
Allow
donotbulkpostalmail
No
new_datacleansingscript
Yes
participatesinworkflow
No
statecode
Active
4f0ea3d9-8f34-e911-867a-0003ff4c4e0b
contact
252500091
contact
false
0
false
Create
And the response, containing the exception:
http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/ExecuteOrganizationServiceFaultFault
urn:uuid:673c84eb-0318-4305-b8b0-7be7924f01e6
00000000-0000-0000-0000-000000000000
2020-01-25T15:24:59.669Z
2020-01-25T15:29:59.669Z
s:Sender
A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
baa5a4b8-20c6-4d59-a6e8-6397ff891553
-2147088238
ApiExceptionSourceKey
Plugin/Microsoft.Crm.Common.ObjectModel.ContactService
ApiOriginalExceptionKey
Microsoft.Crm.CrmException: A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again. ---> Microsoft.Crm.CrmException: A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
at Microsoft.Crm.Platform.Server.DataEngine.EntityCrudManager.ThrowDuplicateRecordException(IBusinessEntity entity, ExecutionContext context, SqlException e)
at Microsoft.Crm.Platform.Server.DataEngine.EntityCrudManager.Update(IBusinessEntity entity, FilterExpression filter, ExecutionContext context)
at Microsoft.Crm.BusinessEntities.BusinessProcessObject.DoUpdate(IBusinessEntity entity, FilterExpression filter, ExecutionContext context)
--- End of inner exception stack trace ---
at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)
at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action, PipelineExecutionContext context)
at Microsoft.Crm.Extensibility.Pipeline.<>c__DisplayClass3_0.b__0()
ApiStepKey
90750cb3-cfdc-db11-8341-0019b9204da9
ApiDepthKey
2
ApiActivityIdKey
baa5a4b8-20c6-4d59-a6e8-6397ff891553
ApiPluginSolutionNameKey
System
ApiStepSolutionNameKey
System
ApiExceptionCategory
ClientError
ApiExceptionMesageName
DuplicateRecordEntityKey
ApiExceptionHttpStatusCode
412
DuplicateEntity
******************************************
DuplicateAttributes
**********@*******.com
http://go.microsoft.com/fwlink/?LinkID=398563&error=Microsoft.Crm.CrmException:80060892&client=platform
A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
2020-01-25T15:24:59.6694242Z
false
baa5a4b8-20c6-4d59-a6e8-6397ff891553
-2147088238
ApiExceptionSourceKey
Plugin/Microsoft.Crm.Common.ObjectModel.ContactService
ApiOriginalExceptionKey
Microsoft.Crm.CrmException: A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again. ---> Microsoft.Crm.CrmException: A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
at Microsoft.Crm.Platform.Server.DataEngine.EntityCrudManager.ThrowDuplicateRecordException(IBusinessEntity entity, ExecutionContext context, SqlException e)
at Microsoft.Crm.Platform.Server.DataEngine.EntityCrudManager.Update(IBusinessEntity entity, FilterExpression filter, ExecutionContext context)
at Microsoft.Crm.BusinessEntities.BusinessProcessObject.DoUpdate(IBusinessEntity entity, FilterExpression filter, ExecutionContext context)
--- End of inner exception stack trace ---
at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)
at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action, PipelineExecutionContext context)
at Microsoft.Crm.Extensibility.Pipeline.<>c__DisplayClass3_0.b__0()
ApiStepKey
90750cb3-cfdc-db11-8341-0019b9204da9
ApiDepthKey
2
ApiActivityIdKey
baa5a4b8-20c6-4d59-a6e8-6397ff891553
ApiPluginSolutionNameKey
System
ApiStepSolutionNameKey
System
ApiExceptionCategory
ClientError
ApiExceptionMesageName
DuplicateRecordEntityKey
ApiExceptionHttpStatusCode
412
A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
2020-01-25T15:24:59.6694242Z
false
baa5a4b8-20c6-4d59-a6e8-6397ff891553
-2147088238
ApiExceptionSourceKey
Plugin/Microsoft.Crm.Common.ObjectModel.ContactService
ApiOriginalExceptionKey
Microsoft.Crm.CrmException: A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again. ---> Microsoft.Crm.CrmException: A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
at Microsoft.Crm.Platform.Server.DataEngine.EntityCrudManager.ThrowDuplicateRecordException(IBusinessEntity entity, ExecutionContext context, SqlException e)
at Microsoft.Crm.Platform.Server.DataEngine.EntityCrudManager.Update(IBusinessEntity entity, FilterExpression filter, ExecutionContext context)
at Microsoft.Crm.BusinessEntities.BusinessProcessObject.DoUpdate(IBusinessEntity entity, FilterExpression filter, ExecutionContext context)
--- End of inner exception stack trace ---
at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)
at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action, PipelineExecutionContext context)
at Microsoft.Crm.Extensibility.Pipeline.<>c__DisplayClass3_0.b__0()
ApiStepKey
90750cb3-cfdc-db11-8341-0019b9204da9
ApiDepthKey
2
ApiActivityIdKey
baa5a4b8-20c6-4d59-a6e8-6397ff891553
ApiPluginSolutionNameKey
System
ApiStepSolutionNameKey
System
ApiExceptionCategory
ClientError
ApiExceptionMesageName
DuplicateRecordEntityKey
ApiExceptionHttpStatusCode
412
A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
2020-01-25T15:24:59.6694242Z
false
baa5a4b8-20c6-4d59-a6e8-6397ff891553
-2147088238
A record that has the attribute values Email already exists. The entity key EmailAlternateKey requires that this set of attributes contains unique values. Select unique values and try again.
2020-01-25T15:24:59.6694242Z
false
As for me, it looks ok. It wants to create a new_invoice_relationship entity, which has two related entities in it.
One is the new_invoice entity itself, which has an EntityState of Unchanged.
The second one is a Contact entity (through the contact_new_invoice_relationship field) and it has an EntityState of Changed, which is correct becase some values are updated.
I wish someone could help, or point me in the right direction. Sorry for the lenghty description. I can provide more info, if you need!
It's a very annoying problem for me.
Any ideas?
Thanks in advance,
Attila