locked
crm sdk service.retrieve does not get all columns RRS feed

  • Question

  • I am trying to retrieve various fields from a CRM 2011 entity using the CRM SDK and service.retieve method. It does not retrieve either all the columns or all the columns requested. So I have code which is ...

    #region "get a new incident with just the fields to update"
    string[] incidentfields = new string[] { "createdon",
                                             "qubic_servicemodule_engineerstarttime", 
                                             "qubic_case_status", 
                                             "qubic_servicemodule_engineer", 
                                             "incidentid", 
                                             "qubic_servicemodule_initialqueue",
                                             "qubic_servicemodule_queue",
                                             "ticketnumber",
                                             "qubic_servicemodule_responsetime",
                                             "qubic_servicemodule_servicelevel",
                                             "qubic_servicemoule_fixdeadline",
                                             };
    //var incident2entity = service.Retrieve(Incident.EntityLogicalName, caseid, new Microsoft.Xrm.Sdk.Query.ColumnSet(incidentfields));
    var incident2entity = service.Retrieve(Incident.EntityLogicalName, caseid, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
    #endregion
    
    if (incident2entity != null)
    {
        Incident incident2 = incident2entity.ToEntity<Incident>();
    

    Two versions of the code there, one requesting a subset of columns and one requesting all data from the entity. For some reason only six columns are retrieved. Some, including specifically the 'createdon' field, are returned as null. Why would CRM not play ball here?

    Monday, June 9, 2014 10:33 AM

All replies

  • Brand,

    I think your system has special customizations due to your process. Crm can not show a not null field as null. Check your system , is there any fieldlevelsecurity and maybe some custom code working on incident entity retrieve or retrievemultiple plugin?


    Polat Aydın Crm Software Developer

    Monday, June 9, 2014 10:48 AM
  • Hi,
    first of all ColumnSet(true) returns only the fields containing a value, for this you get only some columns when you use it.
    The field createdon can't return null, you are checking the createdon property of the incident2entity?

    if (incident2entity.Contains("createdon")){
        var createdon = (DateTime)incident2entity["createdon"];
    }

    or the CreatedOn of your incident2 object? (incident2.CreatedOn) this because maybe something went wrong in the early bound class conversion (but I doubt because it's a standard field, with custom fields it's easier to get this kind of errors)


    My blog: www.crmanswers.net - Rockstar 365 Profile

    Monday, June 9, 2014 10:55 AM
  • Yes it does have customisations, I wrote them. But that is why I highlighted the failure of CRM to retrieve the createdon field. That is a core field in a core entity, is defined as not nullable by CRM, and is filled in by CRM.

    It's not a field level security issue because other plugins retrieving the same data from a different trigger work and an advanced find shows me that data exists in that field for all entities.

    The scenario is that I have a history event for a cases which if the action is to accept a job calculates how many working hours elapsed between a case being logged and accepted, hence the need to retrieve the created on field. That is fired when a user hits the 'accept case' button. It also changes the status of the case from unallocated to allocated which triggers another plugin based on a change in the status field. That plug in can retrieve all data. So

    • user A creates a case, crm fills in the createdon field
    • user A can read the createdon time through advanced find
    • user A accepts a case, creating a history entity. CRM can not retrieve the case createdon field
    • the plug in changes the case state
    • which fires another plug in where CRM can retrieve the case createdon field.

    !

    Monday, June 9, 2014 11:03 AM
  • I think your code works on Incident setstate or update message? Instead of retrieving the data i, you can get the createdon field using Pre or Post Images.

    Polat Aydın Crm Software Developer

    Monday, June 9, 2014 11:13 AM
  • I think your code works on Incident setstate or update message? Instead of retrieving the data i, you can get the createdon field using Pre or Post Images.

    Polat Aydın Crm Software Developer

    No the code fires from IncidentHistory creation. IncidentHistory is a custom entity linked to incident. Hence the need to explicitly retrieve and update fields in the parent entity. The case already exists because the only way to create the incident history is to hit a 'do something' button on the incident after the incident has been created. It is clearly linked correctly because it retrieves some of the data and yet CRM refuses to return all the data.

    The irony is that this was meant to overcome another part of CRM that doesn't work, the failure of FetchXML to adequately handle the retrieval of linked entities.

    Hi,
    first of all ColumnSet(true) returns only the fields containing a value, for this you get only some columns when you use it.
    The field createdon can't return null, you are checking the createdon property of the incident2entity?

    if (incident2entity.Contains("createdon")) {
       var createdon = (DateTime)incident2entity["createdon"];
    }

    or the CreatedOn of your incident2 object? (incident2.CreatedOn) this because maybe something went wrong in the early bound class conversion (but I doubt because it's a standard field, with custom fields it's easier to get this kind of errors)

    Initially I was checking it in the Incident entity after calling Entity.ToEntity as that makes the code cleaner. Since it has shown itself to be failing I've checked immediately after the retreive and the data is definitely not being returned from the CRM SDK.


    • Edited by J N Brand Monday, June 9, 2014 7:04 PM fix typos
    Monday, June 9, 2014 7:03 PM
  • Hi Brand,

    You could try entering in the name of the incident entity as a string instead of using the early binding.

    If that fails, it would be good for us to see the rest of your code. Where is caseid coming from for instance?

    ~ Atomic Coder

    Monday, June 9, 2014 8:05 PM
  • Hi Brand,

    You could try entering in the name of the incident entity as a string instead of using the early binding.

    If that fails, it would be good for us to see the rest of your code. Where is caseid coming from for instance?

    ~ Atomic Coder

    OK, first in the plug in responding to the incident history event we find a load of data including the reference to the case to which this refers. That was defined from the user interface via Javascript

                    if (context.ParentContext.Depth == 1) // avoid recursion
                    {
                        // find the entity that initiated us - bit of double talking here as we need an entity
                        // to get an Id to retrieve the entity that contains that Id
                        var entity = context.InputParameters["Target"] as Entity;
                        string[] fields = new string[] { "qubic_servicemodule_case", "qubic_servicemodule_endtime", "qubic_servicemodule_starttime", "qubic_servicemodule_elapsedtime", "qubic_servicemodule_engineer", "qubic_servicemodule_caseaction", "qubic_servicemodule_updatenotes", "qubic_servicemodule_emailaccountcontact", "qubic_servicemodule_emailcasecontact", "qubic_servicemodule_emailinterestedparties", "qubic_servicemodule_bookedengineer", "qubic_servicemodule_bookedtime", "qubic_servicemodule_courier", "qubic_servicemodule_courierdelivery", "qubic_servicemodule_couriertrackingid", "createdby" };
                        var entity2 = service.Retrieve(qubic_servicemodule_casehistory.EntityLogicalName, entity.Id, new Microsoft.Xrm.Sdk.Query.ColumnSet(fields));
    
                        if (entity != null)
                        {
                            // Now find the case history record
                            qubic_servicemodule_casehistory casehistory = entity2.ToEntity<qubic_servicemodule_casehistory>();
                            // and the case it points to
                            Guid caseid = casehistory.qubic_servicemodule_case.Id;
    

    Then we decide what we're doing with it. In this case I'm only interested in situations where an engineer accepts a job

    //now work out what to do with it
    qubic_servicemodule_caseaction action = (qubic_servicemodule_caseaction)casehistory.qubic_servicemodule_caseaction.Value;
    switch (action)
    {
        case qubic_servicemodule_caseaction.Acceptjob:
            Acceptjob(context, service, caseid, casehistory);
            break;
    

    And then in the accept job procedure we calculate how long we took to get back to the customer.

    private void Acceptjob(IPluginExecutionContext context, IOrganizationService service, Guid caseid, qubic_servicemodule_casehistory casehistory)
    {
        Guid userid = casehistory.CreatedBy.Id;
    
        #region "Assign case as a crm owner"
        AssignRequest assign = new AssignRequest
        {
            Assignee = new EntityReference(SystemUser.EntityLogicalName, userid),
            Target = new EntityReference(Incident.EntityLogicalName, casehistory.qubic_servicemodule_case.Id)
        };
        service.Execute(assign);
        #endregion
    
        #region "get a new incident with just the fields to update"
        string[] incidentfields = new string[] { "createdon",
                                                         "qubic_servicemodule_engineerstarttime", 
                                                         "qubic_case_status", 
                                                         "qubic_servicemodule_engineer", 
                                                         "incidentid", 
                                                         "qubic_servicemodule_initialqueue",
                                                         "qubic_servicemodule_queue",
                                                         "ticketnumber",
                                                         "qubic_servicemodule_responsetime",
                                                         "qubic_servicemodule_servicelevel",
                                                         "qubic_servicemoule_fixdeadline",
                                                         };
                //var incident2entity = service.Retrieve(Incident.EntityLogicalName, caseid, new Microsoft.Xrm.Sdk.Query.ColumnSet(incidentfields));
                var incident2entity = service.Retrieve(Incident.EntityLogicalName, caseid, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
                #endregion
    
        if (incident2entity != null)
        {
            Incident incident2 = incident2entity.ToEntity<Incident>();
    
            #region "Get service level"
            qubic_servicelevel sl = servicecase.GetServiceLevel(service, incident2);
            #endregion
    
            EntityReference engineer = new EntityReference
            {
                Id = userid,
                LogicalName = "systemuser"
            };
    
            #region "Find support hours"
            Boolean[, ,] supporthours;
            servicecase.GetSupportHours(service, sl, out supporthours);
            #endregion
    
            #region "Set engineer and current state"
            incident2.qubic_servicemodule_Engineer = engineer;
            incident2.qubic_case_Status.Value = (int)(qubic_casestatus.Allocated);
            incident2.qubic_servicemodule_engineerstarttime = System.DateTime.Now;
            incident2.qubic_servicemodule_Queue = incident2.qubic_servicemodule_Initialqueue;
            #endregion
    
            #region "Set the response time"
            try
            {
                if (!incident2.qubic_servicemodule_responsetime.HasValue)
                {
                    DateTime RespondedOn = casehistory.CreatedOn.HasValue ? casehistory.CreatedOn.Value : DateTime.Now;
                    TimeSpan responsets = servicecase.FindWorkTime(service, incident2, incident2.CreatedOn.Value, RespondedOn);
                    incident2.qubic_servicemodule_responsetime = responsets.TotalHours;
                }
            }
            catch (Exception e)
            {
            }
            #endregion
    

    However I don't believe that to be the issue because other fields retrieved from the case are providing valid data, for example the support level and support hours which vary by customer, contract etc are returned and calculated correctly.


    Tuesday, June 10, 2014 3:00 PM
  • and just to add to the wierdness. If I add ...

                            // For testing only get the case details
                            #region "get a new incident with just the fields to update"
                            string[] incidentfields = new string[] { "createdon",
                                                                     "qubic_servicemodule_engineerstarttime", 
                                                                     "qubic_case_status", 
                                                                     "qubic_servicemodule_engineer", 
                                                                     "incidentid", 
                                                                     "qubic_servicemodule_initialqueue",
                                                                     "qubic_servicemodule_queue",
                                                                     "ticketnumber",
                                                                     "qubic_servicemodule_responsetime",
                                                                     "qubic_servicemodule_servicelevel",
                                                                     "qubic_servicemoule_fixdeadline",
                                                                     };
                            //var incident2entity = service.Retrieve(Incident.EntityLogicalName, caseid, new Microsoft.Xrm.Sdk.Query.ColumnSet(incidentfields));
                            var incident2entity = service.Retrieve(Incident.EntityLogicalName, caseid, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
                            #endregion
    
                            if (incident2entity != null)
                            {
                                Incident incident2 = incident2entity.ToEntity<Incident>();
                                casehistory.qubic_servicemodule_Starttime = incident2.CreatedOn;
                            }
                            #region "get a new incident with just the fields to update"
    

    immediately after the start of the plug in it retrieves 39 fields, including the troublesome createdon field. If I name just the fields I want it fails to retrieve the createdon field but the code works (well it doesn't crash is perhaps more accurate) so the field must be named and referenced properly.

    Tuesday, June 10, 2014 3:28 PM