Nulls are handled differently by the SDK Web services:
Using the CRM 4.0 SDK webservice and pipeline context, you could always exclude an attribute from an update by setting it to null. This has now changed:
CRM 4.0:
entity.attributename = null;
CRM 2011:
entity.Remove("attributename");
Data loss when using the RESTfull endpoint
When using the CRM 4.0 SDK Webservices, you could choose to only return certain attribute values and then when updating only update those values provided whilst leaving the rest the same as they were on the server. This is very desirable to facilitate concurrency (we don't want to send any update to an attribute if we are not actually updating it) and to minimise the traffic between the client and server (don't send/return every attribute with each call).
In CRM2011 however using the OData endpoint this is no longer possible. All values must be retrieved and re-set when updating.
For example, we can use projection onto an Entity to manipulate the $select on the OrganisationData.svc:
var queryVar = from c in _context.ContactSet
where c.FullName.Contains(criteria)
select new Contact {
FullName = c.FullName,
Telephone1 = c.Telephone1,
EMailAddress1 = c.EMailAddress1,
FirstName = c.FirstName,
LastName = c.LastName,
Address1_Line1 = c.Address1_Line1,
Address1_City = c.Address1_City,
Address1_StateOrProvince = c.Address1_StateOrProvince,
Address1_PostalCode = c.Address1_PostalCode
};
This code uses the following GET:
http://{server}:5555/{orgname}/xrmservices/2011/organizationdata.svc/ContactSet()?$filter=FullName%20eq%20'{crtieria}'&$select=FullName,Telephone1,EMailAddress1,etc...
This will only pull down the attributes we need to display.
All good so far.
However, when using the DataContext to update the record on the server using:
_context.BeginSaveChanges(OnSaveContactsComplete, TheMainViewModel.Contacts);
...
We find that all the data that we didn't include in the $select is now nulled out.
This is a common problem with ADO.Net data services and is indeed detailed as "Data loss might occur in the data service when you save updates that were made to projected types." in http://msdn.microsoft.com/en-us/library/ee473425.aspx
This seems like a big flaw to the OData endpoint - in that it forces us to retrieve all values if we want to make any updates at all via the Client OData API. This might be a good reason to avoid the RESTful endpoint unless you know up front that you will never be updating data. The overhead having to retrieving *all* values before performing an update is not something that you want.
There is always an exception...
Since JScript RESTful operations use the JSON notation to send data to the server rather than the OData framework, we can perform partial updates as shown by this JScript in the SDK example 'JScriptRestDataOperations:
function updateAccountRecord(Id) {
var updateAccountReq = new XMLHttpRequest();
var changes = new Object();
changes.Name = "Updated Sample";
changes.Telephone1 = "555-0123";
changes.AccountNumber = "ABCDEFGHIJ";
changes.EMailAddress1 = "someone1@example.com";
updateAccountReq.open("POST", ODataPath + "/AccountSet(guid'" + Id + "')", true);
updateAccountReq.setRequestHeader("Accept", "application/json");
updateAccountReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
updateAccountReq.setRequestHeader("X-HTTP-Method", "MERGE");
updateAccountReq.onreadystatechange = function () {
updateAccountReqCallBack(this, Id);
};
updateAccountReq.send(JSON.stringify(changes));
}
This code will only update the Name, Telephone1, AccountNumber and EmailAddress1 attributes, and leave the rest unchanged. Note that the attribute names are Case Sensitive.