2

I am currently developing a MS Dynamics CRM 2013 - Plugin. When I try to assign a string-value to a key of a field of an entity it gives me the 'keynotfound'-exception.

This leaves me clueless, because I can verify the key is existing. The key I give is also written correctly, and the data types are compatible, too.

Here's some extra info:

  • I tried resolving the issue with a server reboot. Nothing.
  • Remote Debugging is not an option.
  • I swapped "retrieved.EntityCollection.Entities[i][forField]" with retrieved.EntityCollection.Entities[i]["new_name"] and everything was working fine (kind of pointing out the obvious here, but "new_name" is not the key I try to access).
  • The execution stops @ "if (retrieved.EntityCollection.Entities[i][forField].ToString() != "" && !overwriteExisting)"

Have you got an idea to help me out?

public void GenerateNumberForEntityCollection(string target)
{
    try
    {
        // variables for number generation
        bool overwriteExisting = (bool)preImageEntity["new_overwriteexisting"];
        int suffixstart = (int)preImageEntity["new_suffixstart"];
        string forField= preImageEntity["new_forfield"].ToString();
        string prefix = preImageEntity["new_prefix"].ToString();
        string postfix = preImageEntity["new_postfix"].ToString();
        string separator = preImageEntity["new_separator"].ToString();

        // Build query to get all the entries
        RetrieveMultipleResponse retrieved;
        int PageNumber = 1;
        string PagingCookie = string.Empty;
        int PageSize = 5000;
        string[] Columns = { forField };
        QueryExpression query = new QueryExpression()
        {
            EntityName = target,
            ColumnSet = new ColumnSet(Columns),
            PageInfo = new PagingInfo()
            {
                PageNumber = 1,
                Count = PageSize
            }
        };

        do
        {
            if (PageNumber != 1)
            {
                query.PageInfo.PageNumber = PageNumber;
                query.PageInfo.PagingCookie = PagingCookie;
            }

            RetrieveMultipleRequest retrieve = new RetrieveMultipleRequest();
            retrieve.Query = query;
            retrieved = (RetrieveMultipleResponse)service.Execute(retrieve);

            // Now that all entities are retrieved, iterate through them to gen. the numbers
            int i = 0;
            foreach (Entity entity in retrieved.EntityCollection.Entities)
            {
                if (retrieved.EntityCollection.Entities[i][forField].ToString() != "" && !overwriteExisting)
                {
                    //continue;
                }
                else
                {
                    retrieved.EntityCollection.Entities[i][forField] = prefix + separator + suffixstart.ToString() + separator + postfix;
                }
                suffixstart++;
                service.Update(retrieved.EntityCollection.Entities[i]);
                i++;
            }
            if (retrieved.EntityCollection.MoreRecords)
            {
                PageNumber++;
                PagingCookie = retrieved.EntityCollection.PagingCookie;
            }
        } while (retrieved.EntityCollection.MoreRecords);
    }
    catch (Exception e)
    {
        tracing.Trace("GenerateNumberForEntityCollection: Failed: {0}", e.ToString());
    }
}
Henk van Boeijen
  • 7,357
  • 6
  • 32
  • 42
ChrisJu
  • 35
  • 8

3 Answers3

3

How did you verify that the key exists?

If the data in a field is null, the Entity instance will not contain that key, even if you specify it in the query's ColumnSet.

This will return you a boolean, indicating if the key exists in the Entity. You can do this control before attempting to read the attribute.

var attributeExists = retrieved.EntityCollection.Entities[i].Contains(forField) 

The control below you've done will result in the exception you're getting if the field is null. Just make sure that the attribute exists before.

retrieved.EntityCollection.Entities[i][forField].ToString() != ""

Additionally, you'll get a null reference exception if no records were returned from the query. Make you do a null check on retrieved.EntityCollection.Entities.

tdgtyugdyugdrugdr
  • 786
  • 4
  • 13
  • 31
  • 1
    I would not advise to check if the attribute collection actually contains a specific member. The preferred method is to use the `GetAttribute` method. Also, the `DataCollection` returned by `IOrganizationService.RetrieveMultiple` (like in `retrieved.EntyCollection.Entities`) is always present, so a `null` check is not needed there either. – Henk van Boeijen Apr 22 '16 at 05:22
2

When you are querying data in Dynamics CRM it is important to know that record fields having null values in the database are not included in the Attributes collection of the Entity instances being returned.

Getting a value from an Entity's Attribute with this construct:

var value = retrieved.EntityCollection.Entities[i][forField].ToString();

succeeds when attribute forField already has a value in the database, but fails when its current value is null.

Therefore the preferred method to get the attribute values from an entity is GetAttributeValue<T>, like this:

var value = retrieved.EntityCollection.Entities[i].getAttributeValue<string>(forField);

This method returns the value when the attribute exists in the attribute collection, otherwise it returns null.

Henk van Boeijen
  • 7,357
  • 6
  • 32
  • 42
1

If any of the fields among (new_forfield,new_prefix,new_postfix,new_separator) has null value, that column does not present in the retrieved object and you are trying to get the value of null column preImageEntity["new_forfield"] which will throw keynotfound'-exception ,
so change the code

string forField= preImageEntity["new_forfield"].ToString();
string prefix = preImageEntity["new_prefix"].ToString();
string postfix = preImageEntity["new_postfix"].ToString();
string separator = preImageEntity["new_separator"].ToString();

to

string forField = preImageEntity.Attributes.Contains("new_forfield")? preImageEntity["new_forfield"].ToString():"";
string prefix = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_prefix"].ToString() : "";
string postfix = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_postfix"].ToString() : "";
string separator = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_separator"].ToString() : "";  

this will check for field, if it exists than will parse the value to string else will assign empty string.

mzh
  • 515
  • 8
  • 21