Источник:
http://blogs.msdn.com/b/crm/archive/...lverlight.aspx
==============
When you update records using Silverlight and the REST Endpoint for Web resources, unless you have worked around this issue you are updating every field even if the data hasn’t changed. This can lead to the following problems:
- Potential for data loss
- Auditing data does not correctly reflect actual changes
- Event driven features such as Workflows (Processes) and Plug-ins execute when they are not needed
This post will describe the issue and provide a technique to avoid the problems.
Issue Description
The
Microsoft Dynamics CRM SDK documents the following in the topic:
Perform Basic Data Operations in Microsoft Dynamics CRM Using the REST Endpoint.
This behavior is a result of the way that a Silverlight application project generates proxies to work with an OData service. By default all properties defined for an entity are sent in an update request when you use the
DataServiceContext.BeginSaveChanges Method. If you are working with an entity instance that was retrieved from a query it will contain all the current values and saving changes will update all the properties of the entity instance with those values even if they have not changed. If you instantiate a new entity instance and only update a few properties the update will overwrite other properties using the default null value for properties you haven’t set.
Technique to Avoid this Problem
To address this problem you need to provide some capability in your Silverlight application to track which properties have changed and only submit those properties when you save changes. Michael created the following solution that extends the Data Service Context to include change tracking for entity properties. I’ve found that it is relatively easy to apply this to an existing Silverlight application. Use the following steps to add and edit a new class file to your project:
Apply Data Service Context Extensions to A Silverlight Application Project:
1. Add a reference to System.Xml.Linq to your Silverlight application project if it doesn’t already exist
2. Create a new class file for your Silverlight application project. You might call it DataServiceContextExtensions.cs.
3. Paste the following code into the new file:
using System;using System.Linq;using System.Data.Services.Client;using System.Reflection;using System.Collections.Generic;using System.ComponentModel;using System.Collections.ObjectModel;using System.Xml.Linq;namespace [[The Namespace of your Data Service Context]]{ partial class [[The name of your DataServiceContext Class]] { #region Methods partial void OnContextCreated() { this.ReadingEntity += this.OnReadingEntity; this.WritingEntity += this.OnWritingEntity; } #endregion #region Event Handlers private void OnReadingEntity(object sender, ReadingWritingEntityEventArgs e) { ODataEntity entity = e.Entity as ODataEntity; if (null == entity) { return; } entity.ClearChangedProperties(); } private void OnWritingEntity(object sender, ReadingWritingEntityEventArgs e) { ODataEntity entity = e.Entity as ODataEntity; if (null == entity) { return; } entity.RemoveUnchangedProperties(e.Data); } #endregion } public abstract class ODataEntity { private readonly Collection<span style="color: #0000ff"string/span> ChangedProperties = new Collection<span style="color: #0000ff"string/span>(); public ODataEntity() { EventInfo info = this.GetType().GetEvent("PropertyChanged"); if (null != info) { PropertyChangedEventHandler method = new PropertyChangedEventHandler
(this.OnEntityPropertyChanged);
//Ensure that the method is not attached and reattach it info.RemoveEventHandler(this, method); info.AddEventHandler(this, method); } } #region Methods public void ClearChangedProperties() { this.ChangedProperties.Clear(); } internal void RemoveUnchangedProperties(XElement element) { const string AtomNamespace = "http://www.w3.org/2005/Atom"; const string DataServicesNamespace = "http://schemas.microsoft.com/ado/2007/08/dataservices"; const string DataServicesMetadataNamespace = DataServicesNamespace + "/metadata"; if (null == element) { throw new ArgumentNullException("element"); } List properties = (from c in element.Elements(XName.Get("content", AtomNamespace) ).Elements(XName.Get("properties", DataServicesMetadataNamespace)).Elements() select c).ToList(); foreach (XElement property in properties) { if (!this.ChangedProperties.Contains(property.Name.LocalName)) { property.Remove(); } } } private void OnEntityPropertyChanged(object sender,
System.ComponentModel.PropertyChangedEventArgs e)
{ if (!this.ChangedProperties.Contains(e.PropertyName)) { this.ChangedProperties.Add(e.PropertyName); } } #endregion }}
4. In the file you created replace the following placeholders with the correct references for your project:
5. Update the Reference.cs file
a. In Visual Studio 2010, click the icon with the tooltip Show All Files at the top of the Solution Explorer window.
b. In Solution Explorer, expand the service reference you created and the Reference.datasvcmap file to view the Reference.cs file.
c. Use Find/Replace to change:
: global::System.ComponentModel.INotifyPropertyChanged
to
: ODataEntity, global::System.ComponentModel.INotifyPropertyChanged
Note: There should be one instance for each entity.
6. Recompile your project, update your Silverlight Web resource with the new .xap file and test it.
SDK Update
In next release of the SDK (version 5.05) the SDK topic
Use the REST Endpoint with Silverlight Web Resources will contain steps include this method. Each of the Silverlight samples that update records will also be updated to include these extensions.
Cheers,
Jim Daly,
Michael Scott
Источник:
http://blogs.msdn.com/b/crm/archive/...lverlight.aspx