i have a wcf which connects to crm (on prem) to retrieve an account record. i can see when the entity is retrieved it does not hold the current record i.e. some field will still hold the old column value. i tried with various merge option with no avail. please see the code below
using (XrmServiceContext cContext = new XrmServiceContext(con))
{
Entity ent = cContext.Retrieve(ConstantKVP.AccountSchema.ENTITY_LOGICAL_NAME, AccountId, new ColumnSet(true));
}
any suggestions?
Is it possible the data is being cached?
cContext.TryAccessCache(cache => cache.Mode = OrganizationServiceCacheMode.Disabled);
I took this approach for a CrmOrganizationServiceContext, so perhaps the same theory applies.
After save use clear changes cContext.ClearChanges();
For retrieves use MergeOption.OverwriteChanges
Or
Create a new XrmServiceContext object by passing a newed up organizationservice:
var uncachedOrganizationService = new OrganizationService("Xrm");
var uncachedXrmServiceContext = new XrmServiceContext(uncachedOrganizationService);
var ent = uncachedXrmServiceContext.Retrieve(ConstantKVP.AccountSchema.ENTITY_LOGICAL_NAME,AccountId,new ColumnSet(true));
Related
Is there any way to track changes to Metadata, like new fields, new entities and so on?
It is difficult to control a very large project in the same environment, so sometimes there are some customization that should not be deployed to productions (Mostly are mistakes or test in a development environment).
And there is a way to know who did that customization?
I am looking to know every possible change, not any in particular.
You have to use the RetrieveMetadataChangesRequest and it is not possible to know who made the change.
This is available only from Microsoft Dynamics CRM 2011 Update Rollup 12
This request is intended to be used to cache information from the metadata and be able to work offline, but we can use it to track changes to metadata in complex projects and complex teams
Examples on internet are not very friendly so this is how you can use the request:
The request can be completed only with filling one parameter
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
ClientVersionStamp = null
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
The first time you executed this request ClientVersionStamp needs to be null, because there was no request made to the metadata before and there is no ClientVersionStamp. This parameter is the last time you query for metadata changes and if it is null it will bring all customization from all time, so probably this request won't complete on time so we need to tune up.
var EntityFilter = new MetadataFilterExpression(LogicalOperator.And);
EntityFilter.Conditions.Add(new MetadataConditionExpression("SchemaName", MetadataConditionOperator.Equals, "ServiceAppointment"));
var entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter
};
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = null
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
This will query all metadata changes for "ServiceAppointment", feel free to use the entity you want, but what we need is the ServerTimeStamp from the response, it will looks like "22319800!09/13/2017 16:17:46", if you try to send this time stamp first, it will throw an exception, so it is necessary to query first to get a server time stamp.
Now you can use the request and the time stamp to retrieve all new changes since "22319800!09/13/2017 16:17:46"
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = #"22319800!09/13/2017 16:17:46"
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
You can filter the query to match your needs, only search for specific entities, labels, relationship, keys and attributes or specific properties.
EntityQueryExpression entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter,
Properties = EntityProperties,
RelationshipQuery = new RelationshipQueryExpression()
{
Properties = RelationshipProperties,
Criteria = RelationshipFilter
},
AttributeQuery = new AttributeQueryExpression()
{
Properties = AttributeProperties,
Criteria = AttributeFilter
}
};
Use this request and implement it the way you need.
A couple more options:
Register a plugin on Publish and Publish All, and track who did
the publish and when. That may help you narrow down who was making
changes, although someone could technically make a change without
publishing it, so not perfect information.
If you're using Dynamics OnPremise, the Metadata tables sometimes store information about who made a change that is not visible through a Metadata retrieve. I've found this to be very spotty though, not all Metadata has a Modified By user stored.
I am using Ms Dynamic Web Api with Simple OData. I need to add new record for link entities.
I am using the below code snip and refer the documentation on
https://github.com/object/Simple.OData.Client/wiki/Adding-entries-with-links
var newContactData = await _oDataClient
.For<Contacts>()
.Set(new
{
firstname = contactData.ContatDetails.firstname,
lastname = contactData.ContatDetails.lastname,
emailaddress1 = contactData.ContatDetails.emailaddress1
})
.InsertEntryAsync(true);
var newContactLink = await _oDataClient.For<New_project_contactses>()
.Set(new
{
_new_contact_project_name_new_value = contactData.ContatDetailsLink._new_contact_project_name_new_value,
new_project_contactsid = new Guid("0eb46b24-21a2-e611-80eb-c4346bc5b2d4"),
new_contact_type = contactData.ContatDetailsLink.new_contact_type,
})
.InsertEntryAsync(resultRequired: true);
i am getting exception
CRM do not support direct update of Entity Reference properties, Use
Navigation properties insteadS
Well, it is possible, but you need to use the special "#odata.bind" syntax to update your single-navigation properties.
For example, to update an account so that it references an existing primarycontactid, you can use a PATCH operation to the /api/data/v8.2/accounts endpoint with the following body:
{
"name":"Sample Account",
"primarycontactid#odata.bind":"/contacts(00000000-0000-0000-0000-000000000001)"
}
See https://msdn.microsoft.com/en-us/library/gg328090.aspx#Anchor_3 (it is discussed in terms of creating an entity, but it works for updating as well).
I figure out the issue With Dynamc CRM you cannot directly update reference entities Field. You can identify reference entity properties start with "_".
I'm really scratching my head with this. I'm trying to use the Dynamics CRM SDK to update an account record. No matter what I try, it's failing. Here goes.
Account sampleAccount = CrmAccount.GetAccountsBySubmissionCode(crmService, "ERZZUP").Single<Account>();
sampleAccount.Name = "AMC Edited";
crmService.Update(sampleAccount);
Gives the error: EntityState must be set to null, Created (for Create message) or Changed (for Update message)
XrmServiceContext ctx = new XrmServiceContext(crmService);
Account sampleAccount = CrmAccount.GetAccountsBySubmissionCode(crmService, "ERZZUP").Single<Account>();
sampleAccount.Name = "AMC Edited";
ctx.UpdateObject(sampleAccount);
ctx.SaveChanges();
Gives the error: The context is not currently tracking the 'account' entity.
XrmServiceContext ctx = new XrmServiceContext(crmService);
Account sampleAccount = CrmAccount.GetAccountsBySubmissionCode(crmService, "ERZZUP").Single<Account>();
sampleAccount.Name = "AMC Edited";
ctx.Attach(sampleAccount);
ctx.UpdateObject(sampleAccount);
ctx.SaveChanges();
Gives the error: The 'account' entity is already attached to a context.
For reference,
1. The Account object is created by the SDK Early Bound Code Generation Tool
2. crmService is the IOrganizationService connection object
3. GetAccounts ... performs a LINQ query and return an IEnumerable
Please help.
Thanks,
Chris.
Refer to http://msdn.microsoft.com/en-us/library/gg695783.aspx, particularly the "Multiple Data Contexts" part. It seems you're using multiple contexts to track the entities. The CrmAccount.GetAccountsBySubmissionCode method just hides this from you.
Make sure within the CrmAccount.GetAccountsBySubmissionCode method to dispose of the context/service before returning the IEnumerable<Account>, or make sure you use the same context/service to Update.
I notice the the CRM moderator David Jennaway on the technet forum states that you can't use LINQ to update/Create records in CRM 2011 see here http://social.microsoft.com/Forums/en-IE/crmdevelopment/thread/682a7be2-1c07-497e-8f58-cea55c298062
But I have seen a few threads that make it seem as if it should work. Here is my attempt which doesn't work. Any ideas why not?
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
OrganizationServiceContext orgContext = new OrganizationServiceContext(service);
EntityState state = new EntityState();
state = EntityState.Changed;
var counter = from c in orgContext.CreateQuery<pcx_entitycounter>()
where c.pcx_name.Contains("pcx_candidate")
select new pcx_entitycounter
{Id = c.Id,
pcx_name = c.pcx_name, pcx_Sequence = c.pcx_Sequence, pcx_Prefix = c.pcx_Prefix
};
foreach (var c in counter)
{
string prefix = c.pcx_Prefix.ToString(); ;
string sequence = c.pcx_Sequence.ToString();
c.pcx_Sequence = c.pcx_Sequence + 1;
c.EntityState = state;
**service.Update(c);** //FAILS HERE
}
In my experience, it's been difficult-to-impossible to retrieve an entity from the Context, update it, then use the Service to save the changes. It has caused me headaches figuring it out!
Since your retrieval code uses a query from the Context, all of those entities should be attached to the Context and their states are being tracked. Thus you need to use the Context's method for updating:
foreach (var c in counter) {
string prefix = c.pcx_Prefix.ToString(); ;
string sequence = c.pcx_Sequence.ToString();
c.pcx_Sequence = c.pcx_Sequence + 1;
// Use the Context to save changes
orgContext.UpdateObject(c);
orgContext.SaveChanges();
}
Since a lot of my code will retrieve entities in different ways (i.e. Service or Context) depending on the situation, I have developed a simple method that knows how to update the entity correctly. To expand on your example, you might have an update method that looks like:
public void UpdatePcxEntityCounter(pcx_entitycounter c) {
if (!orgContext.IsAttached(c)) {
service.Update(c);
}
else {
orgContext.UpdateObject(c);
orgContext.SaveChanges();
}
}
This assumes both orgContext and service are available at a scope above that of the method. Otherwise, they'd have to be passed as additional parameters.
Without seeing the difficult its difficult to discern what the issue is but have you tried using orgContext.UpdateObject(c); before doing the update step? Also, not sure why you are assigning the prefix and sequence to local variables within your loop since they don't appear to be being used. Its possible that you are getting a SOAP Exception or something for assigning values that don't work. Do you have any plugins registered on the entity?
See the following links for possible resolutions -
How to update a CRM 2011 Entity using LINQ in a Plugin?
http://social.microsoft.com/Forums/en-US/crmdevelopment/thread/7ae89b3b-6eca-4876-9513-042739fa432a
I am trying to create a new contact using Dynamic Entity. The sample i found in CRM SDK had this code.
// Set the properties of the contact using property objects.
StringProperty firstname = new StringProperty();
firstname.Name = "firstname";
firstname.Value = "Jesper";
StringProperty lastname = new StringProperty();
lastname.Name = "lastname";
lastname.Value = "Aaberg";
// Create the DynamicEntity object.
DynamicEntity contactEntity = new DynamicEntity();
// Set the name of the entity type.
contactEntity.Name = EntityName.contact.ToString();
// Set the properties of the contact.
contactEntity.Properties = new Property[] {firstname, lastname};
In my code i have the following implementation.
StringProperty sp_Field1 = new StringProperty("Field1","Value1");
StringProperty sp_Field2 = new StringProperty("Field2","Value1");
CrmService service = new CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Create the DynamicEntity object.
DynamicEntity contactEntity = new DynamicEntity();
// Set the name of the entity type.
contactEntity.Name = EntityName.contact.ToString();
// Set the properties of the contact.
contactEntity.Properties = new Property[] {sp_Field1,sp_Field2};
I don't see much differences in the code. In the examples i found in the internet i have the same implementation as i found in SDK. But if i run the same i get the following error
CS0029: Cannot implicitly convert type 'Microsoft.Crm.Sdk.StringProperty' to 'Microsoft.Crm.Sdk.PropertyCollection'
I tried created a new variable of type PropertyCollection(one that belongs in mscrm namespace) and added the stringpropertys into that and passed it to the entity.
Microsoft.Crm.Sdk.PropertyCollection propTest = new Microsoft.Crm.Sdk.PropertyCollection();
propTest.Add(sp_SSNNo);
propTest.Add(sp_FirstName);
contactEntity.Properties = new Property[] {propTest};
This gave me the following error
CS0029: Cannot implicitly convert type 'Microsoft.Crm.Sdk.PropertyCollection' to 'Microsoft.Crm.Sdk.Property'
I am sure its a minor typecasting error but i am not able to figure out where the error is. And moreover, even if it was a typecasting error why is it working for all the samples given in the internet and not for me. I tried getting the code sample to run but i am encountering the same conversion error. Please let me know if you need more info on this, any help on this would be appreciated.
Here is an article from Microsoft that makes an attempt to discuss this topic:
http://community.dynamics.com/blogs/cscrmblog/archive/2008/06/23/web-services-amp-dlls-or-what-s-up-with-all-the-duplicate-classes.aspx
This is not a bug that you are running into but more of a difference in design between the way the two assemblies work and what they are designed to do.
If you want to continue to use the Microsoft.Crm.Sdk.dll you should be able to accomplish your goal with the following...
StringProperty sp_Field1 = new StringProperty("Field1","Value1");
StringProperty sp_Field2 = new StringProperty("Field2","Value1");
CrmService service = new CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Create the DynamicEntity object.
DynamicEntity contactEntity = new DynamicEntity();
// Set the name of the entity type.
contactEntity.Name = EntityName.contact.ToString();
// Set the properties of the contact.
PropertyCollection properties = new PropertyCollection();
properties.Add(sp_Field1);
contactEntity.Properties = properties;
Thanks SaaS Developer, that code is working fine now. One more way of doing it would be to directly add the StringProperty to the entity property collection.
contactEntity.Properties.Add(sp_SSNNo);
Thanks again for replying :)
I believe the issue is that you are referencing the dynamic entity class in the Microsoft.Crm.Sdk assembly. The sample in the SDK is using a reference to the CRM web service. This can get confusing as both assemblies contain many of the same types, however they are different.