I have been writing some plugins in CRM 2011 and for each plugin I use I usually setup a class which does link querying. To do this I pass the OrganisationServiceContext
In my plugin I create this
// Get a reference to the Organization service.
IOrganizationServiceFactory factory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
Microsoft.Xrm.Sdk.Client.OrganizationServiceContext orgContext =
new Microsoft.Xrm.Sdk.Client.OrganizationServiceContext(service);
I have now have my OrganizationServiceContext which I can use in my Linq queries
public IEnumerable<hosk_candidate> searchCandidateID(Microsoft.Xrm.Sdk.Client.OrganizationServiceContext orgContext, string candidateId)
{
try
{
IEnumerable<hosk_candidate> candidates = from c in orgContext.CreateQuery<hosk_candidate>()
where (c.hosk_CandidateHoskID.Contains(candidateId))
select c;
//hosk_candidate candidate = (hosk_candidate)this.returnOne(candidates);
return candidates;
}
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
{
// You can handle an exception here or pass it back to the calling method.
throw;
}
}
I have class in between the Plugin and Linq query class which gets the results
IEnumerable<hosk_candidate> candidates = linqQueries.searchCandidateID(this.orgContext, searchString);
The reason I have done it like this is so I can easily test the code because it isn’t in the plugin class itself. I can create the OrganisationServiceContext easily and then pass it to the code the same way as the plugin code does.
I have found out that this works slightly unusually with regards to updating the data. When you use Linq queries it Tracks the changes you make, these are tracked by the Service Context.
What this means is if you run a Linq query which returns some data and you then want to update the entity you plugin passed you can’t just add the object.
Initially I was working with an entity, I would then
orgContext.UpdateObject(can);
orgContext.SaveChanges();
add my entity to Context and update and then save like above, this works fine as long as you haven’t been querying different values in your linq query.
I tried to add a different entity to be updated (a different entity than the entities returned by my Linq) query and I kept getting errors thrown up.
I then worked out that I had to attach the entity and then update and save the changes.
orgContext.Attach(can)
orgContext.UpdateObject(can);
orgContext.SaveChanges();
I am now in situation where I do a linq query and if the query doesn’t return any values then I do not need to attach the entity and can just update and save it but if the linq query returns some entities then I need to attach my entity
if (recordUpdate)
{
orgContext.Attach(can);
}
orgContext.UpdateObject(can);
orgContext.SaveChanges();
if (can.statecode == null) { orgContext.AddObject(can); } else { orgContext.Attach(can); } orgContext.UpdateObject(can); orgContext.SaveChanges();
This has taken me a while to work this out. The reason for Linq query returning or not returning results is I am setting an ID on a candidate based on surname, firstname and a counter. I need to search to see if there are any ID’s with that value and if there are then add one to the counter but if this candidate is the first then create it, which is the reason why sometimes the linq queries returns values (and turns on tracking) and sometimes it doesn’t (new ID).
It would have probably helped if I had read this article by Microsoft