Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / AtomMaterializerLog.cs / 1305376 / AtomMaterializerLog.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a class that can keep a record of changes done to the // data service state. // //--------------------------------------------------------------------- namespace System.Data.Services.Client { #region Namespaces. using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Xml; using System.Xml.Linq; using System.Text; #endregion Namespaces. ////// Use this class to keep a log of changes done by the materializer. /// internal class AtomMaterializerLog { #region Private fields. ///Associated data context for the log. private readonly DataServiceContext context; ///Dictionary of identity URI to instances created during previous AppendOnly moves. private readonly DictionaryappendOnlyEntries; /// Dictionary of identity URI to entries with media that aren't otherwise tracked. private readonly DictionaryfoundEntriesWithMedia; /// Dictionary of identity URI to tracked entities. private readonly DictionaryidentityStack; /// List of link descriptors (data for links and state). private readonly Listlinks; /// Merge option used to apply changes. private readonly MergeOption mergeOption; ///Target instance to refresh. private object insertRefreshObject; #endregion Private fields. #region Constructors. ////// Initializes a new /// Associated data context for the log. /// Merge option used to apply changes. ///instance. /// /// Note that the merge option can't be changed. /// internal AtomMaterializerLog(DataServiceContext context, MergeOption mergeOption) { Debug.Assert(context != null, "context != null"); this.appendOnlyEntries = new Dictionary(EqualityComparer .Default); this.context = context; this.mergeOption = mergeOption; this.foundEntriesWithMedia = new Dictionary (EqualityComparer .Default); this.identityStack = new Dictionary (EqualityComparer .Default); this.links = new List (); } #endregion Constructors. #region Internal properties. /// Whether changes are being tracked. internal bool Tracking { get { return this.mergeOption != MergeOption.NoTracking; } } #endregion Internal properties. #region Internal methods. ///Applies all accumulated changes to the associated data context. ///The log should be cleared after this method successfully executed. internal void ApplyToContext() { Debug.Assert( this.mergeOption != MergeOption.OverwriteChanges || this.foundEntriesWithMedia.Count == 0, "mergeOption != MergeOption.OverwriteChanges || foundEntriesWithMedia.Count == 0 - we only use the 'entries-with-media' lookaside when we're not in overwrite mode, otherwise we track everything through identity stack"); if (!this.Tracking) { return; } foreach (KeyValuePairentity in this.identityStack) { AtomEntry entry = entity.Value; if (entry.CreatedByMaterializer || entry.ResolvedObject == this.insertRefreshObject || entry.ShouldUpdateFromPayload) { // Create a new descriptor and try to attach, if one already exists, get the existing reference instead. EntityDescriptor descriptor = new EntityDescriptor(entity.Key, entry.QueryLink, entry.EditLink, entry.ResolvedObject, null, null, null, entry.ETagText, EntityStates.Unchanged); descriptor = this.context.InternalAttachEntityDescriptor(descriptor, false); // we should always reset descriptor's state to Unchanged (old v1 behaviour) descriptor.State = EntityStates.Unchanged; this.ApplyMediaEntryInformation(entry, descriptor); descriptor.ServerTypeName = entry.TypeName; } else { // Refresh the entity state indirectly by calling TryGetEntity. EntityStates state; this.context.TryGetEntity(entity.Key, entry.ETagText, this.mergeOption, out state); } } // Regardless of the merge mode, media link information should // always be applied to the context. foreach (AtomEntry entry in this.foundEntriesWithMedia.Values) { Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise it wasn't found"); EntityDescriptor descriptor = this.context.GetEntityDescriptor(entry.ResolvedObject); this.ApplyMediaEntryInformation(entry, descriptor); } foreach (LinkDescriptor link in this.links) { if (EntityStates.Added == link.State) { // Added implies collection if ((EntityStates.Deleted == this.context.GetEntityDescriptor(link.Target).State) || (EntityStates.Deleted == this.context.GetEntityDescriptor(link.Source).State)) { this.context.DeleteLink(link.Source, link.SourceProperty, link.Target); } else { this.context.AttachLink(link.Source, link.SourceProperty, link.Target, this.mergeOption); } } else if (EntityStates.Modified == link.State) { // Modified implies reference object target = link.Target; if (MergeOption.PreserveChanges == this.mergeOption) { LinkDescriptor end = this.context.GetLinks(link.Source, link.SourceProperty).FirstOrDefault(); if (null != end && null == end.Target) { // leave the SetLink(link.Source, link.SourceProperty, null) continue; } if ((null != target) && (EntityStates.Deleted == this.context.GetEntityDescriptor(target).State) || (EntityStates.Deleted == this.context.GetEntityDescriptor(link.Source).State)) { target = null; } } this.context.AttachLink(link.Source, link.SourceProperty, target, this.mergeOption); } else { // detach link Debug.Assert(EntityStates.Detached == link.State, "not detached link"); this.context.DetachLink(link.Source, link.SourceProperty, link.Target); } } } /// Clears all state in the log. internal void Clear() { this.foundEntriesWithMedia.Clear(); this.identityStack.Clear(); this.links.Clear(); this.insertRefreshObject = null; } ////// Invoke this method to notify the log that an existing /// instance was found while resolving an object. /// /// Entry for instance. internal void FoundExistingInstance(AtomEntry entry) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(ShouldTrackWithContext(entry), "Existing entries should be entity"); if (this.mergeOption == MergeOption.OverwriteChanges) { this.identityStack[entry.Identity] = entry; } else if (this.Tracking && entry.MediaLinkEntry == true) { this.foundEntriesWithMedia[entry.Identity] = entry; } } ////// Invoke this method to notify the log that the /// target instance of a "directed" update was found. /// /// Entry found. ////// The target instance is typically the object that we /// expect will get refreshed by the response from a POST /// method. /// /// For example if a create a Customer and POST it to /// a service, the response of the POST will return the /// re-serialized instance, with (important!) server generated /// values and URIs. /// internal void FoundTargetInstance(AtomEntry entry) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise this is not a target"); if (ShouldTrackWithContext(entry)) { this.context.AttachIdentity(entry.Identity, entry.QueryLink, entry.EditLink, entry.ResolvedObject, entry.ETagText); this.identityStack.Add(entry.Identity, entry); this.insertRefreshObject = entry.ResolvedObject; } } ///Attempts to resolve an entry from those tracked in the log. /// Entry to resolve. /// /// After invocation, an existing entry with the same identity as ///; possibly null. /// /// true if an existing entry was found; false otherwise. internal bool TryResolve(AtomEntry entry, out AtomEntry existingEntry) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(entry.Identity != null, "entry.Identity != null"); if (this.identityStack.TryGetValue(entry.Identity, out existingEntry)) { return true; } if (this.appendOnlyEntries.TryGetValue(entry.Identity, out existingEntry)) { // The AppendOnly entries are valid only as long as they were not modified // between calls to .MoveNext(). EntityStates state; this.context.TryGetEntity(entry.Identity, entry.ETagText, this.mergeOption, out state); if (state == EntityStates.Unchanged) { return true; } else { this.appendOnlyEntries.Remove(entry.Identity); } } existingEntry = null; return false; } ////// Invoke this method to notify the log that a new link was /// added to a collection. /// /// /// Instance with the collection to which/// was added. /// /// Property name for collection. /// Object which was added. internal void AddedLink(AtomEntry source, string propertyName, object target) { Debug.Assert(source != null, "source != null"); Debug.Assert(propertyName != null, "propertyName != null"); if (!this.Tracking) { return; } if (ShouldTrackWithContext(source) && ShouldTrackWithContext(target)) { LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Added); this.links.Add(item); } } /// /// Invoke this method to notify the log that a new instance /// was created. /// /// Entry for the created instance. internal void CreatedInstance(AtomEntry entry) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise, what did we create?"); Debug.Assert(entry.CreatedByMaterializer, "entry.CreatedByMaterializer -- otherwise we shouldn't be calling this"); if (ShouldTrackWithContext(entry)) { this.identityStack.Add(entry.Identity, entry); if (this.mergeOption == MergeOption.AppendOnly) { this.appendOnlyEntries.Add(entry.Identity, entry); } } } ////// Invoke this method to notify the log that a link was removed /// from a collection. /// /// /// Instance with the collection from which/// was removed. /// /// Property name for collection. /// Object which was removed. internal void RemovedLink(AtomEntry source, string propertyName, object target) { Debug.Assert(source != null, "source != null"); Debug.Assert(propertyName != null, "propertyName != null"); if (ShouldTrackWithContext(source) && ShouldTrackWithContext(target)) { Debug.Assert(this.Tracking, "this.Tracking -- otherwise there's an 'if' missing (it happens to be that the assert holds for all current callers"); LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Detached); this.links.Add(item); } } /// /// Invoke this method to notify the log that a link was set on /// a property. /// /// Entry for source object. /// Name of property set. /// Target object. internal void SetLink(AtomEntry source, string propertyName, object target) { Debug.Assert(source != null, "source != null"); Debug.Assert(propertyName != null, "propertyName != null"); if (!this.Tracking) { return; } if (ShouldTrackWithContext(source) && ShouldTrackWithContext(target)) { Debug.Assert(this.Tracking, "this.Tracking -- otherwise there's an 'if' missing (it happens to be that the assert holds for all current callers"); LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Modified); this.links.Add(item); } } #endregion Internal methods. #region Private methods. ////// Returns true if we should track this entry with context /// /// The atom entry ///true if entry should be tracked private static bool ShouldTrackWithContext(AtomEntry entry) { Debug.Assert(entry.ActualType != null, "Entry with no type added to log"); return entry.ActualType.IsEntityType; } ////// Returns true if we should track this entity with context /// /// The resolved instance ///true if entry should be tracked private static bool ShouldTrackWithContext(object entity) { if (entity == null) { // you can set link to null, we need to track these values return true; } ClientType type = ClientType.Create(entity.GetType()); return type.IsEntityType; } ////// Applies the media entry information (if any) to the specified /// /// Entry with (potential) media entry information to apply. /// Descriptor to update. private void ApplyMediaEntryInformation(AtomEntry entry, EntityDescriptor descriptor) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(descriptor != null, "descriptor != null"); if (entry.MediaEditUri != null || entry.MediaContentUri != null) { // if (entry.MediaEditUri != null) { descriptor.EditStreamUri = new Uri(this.context.BaseUriWithSlash, entry.MediaEditUri); } if (entry.MediaContentUri != null) { descriptor.ReadStreamUri = new Uri(this.context.BaseUriWithSlash, entry.MediaContentUri); } descriptor.StreamETag = entry.StreamETagText; } } #endregion Private methods. } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.. ///
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SecurityRuntime.cs
- FtpWebRequest.cs
- InstalledFontCollection.cs
- AggregateNode.cs
- DataGridViewRowPostPaintEventArgs.cs
- ListBox.cs
- EventDescriptorCollection.cs
- RadialGradientBrush.cs
- ThaiBuddhistCalendar.cs
- Errors.cs
- PropertyOrder.cs
- ScriptingSectionGroup.cs
- WrappedIUnknown.cs
- WinInetCache.cs
- Action.cs
- ClrPerspective.cs
- SQLCharsStorage.cs
- HttpCachePolicyBase.cs
- GroupedContextMenuStrip.cs
- PageSettings.cs
- ToggleButton.cs
- AuthenticateEventArgs.cs
- Vertex.cs
- AppDomain.cs
- ParagraphVisual.cs
- DocumentsTrace.cs
- DbSourceCommand.cs
- CommandHelper.cs
- RegionData.cs
- SqlDataSourceEnumerator.cs
- WrappedOptions.cs
- AdRotator.cs
- Serializer.cs
- CodeGotoStatement.cs
- XsdBuildProvider.cs
- NumberSubstitution.cs
- Calendar.cs
- ScrollBar.cs
- Stacktrace.cs
- ColorKeyFrameCollection.cs
- StringAnimationUsingKeyFrames.cs
- SystemException.cs
- SqlDataReaderSmi.cs
- XmlSchemaExporter.cs
- CodeAccessPermission.cs
- TemplatePropertyEntry.cs
- WebEventTraceProvider.cs
- ToolboxDataAttribute.cs
- ComEventsHelper.cs
- DocumentXmlWriter.cs
- Command.cs
- CompensatableTransactionScopeActivity.cs
- Scheduling.cs
- ServicePoint.cs
- SystemColors.cs
- EditorPartChrome.cs
- TreeNodeCollection.cs
- ScriptReferenceBase.cs
- ToolStripContainer.cs
- PeerNameResolver.cs
- DbConnectionPoolCounters.cs
- SharedPersonalizationStateInfo.cs
- DesignerActionHeaderItem.cs
- XappLauncher.cs
- EventMappingSettings.cs
- ThreadAttributes.cs
- SeekableReadStream.cs
- ADMembershipUser.cs
- Rect3DValueSerializer.cs
- OdbcRowUpdatingEvent.cs
- PreProcessor.cs
- HostExecutionContextManager.cs
- UnsafeNativeMethods.cs
- StrongNameIdentityPermission.cs
- DesignerObjectListAdapter.cs
- ToolStripItemTextRenderEventArgs.cs
- ListGeneralPage.cs
- SqlCacheDependency.cs
- WinInetCache.cs
- RoleManagerModule.cs
- MetadataItemEmitter.cs
- Closure.cs
- serverconfig.cs
- SiteMapHierarchicalDataSourceView.cs
- ItemsChangedEventArgs.cs
- BindingMemberInfo.cs
- CustomDictionarySources.cs
- COM2PropertyDescriptor.cs
- XmlSchemaResource.cs
- ProfileGroupSettings.cs
- SqlCacheDependencyDatabase.cs
- SHA512.cs
- MailBnfHelper.cs
- PerspectiveCamera.cs
- Point.cs
- PathFigureCollection.cs
- AuthenticationConfig.cs
- HostedTransportConfigurationManager.cs
- SmiEventSink_DeferedProcessing.cs
- TreeNodeBinding.cs