/// <summary>Enumerates casting each element to a type.</summary> /// <typeparam name="T">Element type to enumerate over.</typeparam> /// <param name="source">Element source.</param> /// <returns> /// An IEnumerable<T> that iterates over the specified <paramref name="source"/>. /// </returns> /// <remarks> /// This method should be unnecessary with .NET 4.0 covariance support. /// </remarks> internal static IEnumerable <T> EnumerateAsElementType <T>(IEnumerable source) { return(ODataEntityMaterializer.EnumerateAsElementType <T>(source)); }
/// <summary> /// Applies the values of the <paramref name="items"/> enumeration to the /// <paramref name="property"/> of the specified <paramref name="entry"/>. /// </summary> /// <param name="entry">Entry with collection to be modified.</param> /// <param name="property">Collection property on the entry.</param> /// <param name="items">Values to apply onto the collection.</param> /// <param name="nextLink">Next link for collection continuation.</param> /// <param name="continuationPlan">Projection plan for collection continuation.</param> /// <param name="isContinuation">Whether this is a continuation request.</param> internal void ApplyItemsToCollection( MaterializerEntry entry, ClientPropertyAnnotation property, IEnumerable items, Uri nextLink, ProjectionPlan continuationPlan, bool isContinuation) { Debug.Assert(entry.Entry != null || entry.ForLoadProperty, "ODataResource should be non-null except for LoadProperty"); Debug.Assert(property != null, "property != null"); Debug.Assert(items != null, "items != null"); IEnumerable <object> itemsEnumerable = ODataEntityMaterializer.EnumerateAsElementType <object>(items); // Populate the collection property with items collection. object collection = this.PopulateCollectionProperty(entry, property, itemsEnumerable, nextLink, continuationPlan); // Get collection of all non-linked elements in collection and remove them except for the ones that were obtained from the response. if (this.EntityTrackingAdapter.MergeOption == MergeOption.OverwriteChanges || this.EntityTrackingAdapter.MergeOption == MergeOption.PreserveChanges) { var linkedItemsInCollection = this.EntityTrackingAdapter .EntityTracker .GetLinks(entry.ResolvedObject, property.PropertyName) .Select(l => new { l.Target, l.IsModified }); if (collection != null && !property.IsDictionary) { var nonLinkedNonReceivedItemsInCollection = ODataEntityMaterializer.EnumerateAsElementType <object>((IEnumerable)collection) .Except(linkedItemsInCollection.Select(i => i.Target)) .Except(itemsEnumerable).ToArray(); // Since no link exists, we just remove the item from the collection foreach (var item in nonLinkedNonReceivedItemsInCollection) { property.RemoveValue(collection, item); } } // When the first time a property or collection is being loaded, we remove all items other than the ones that we receive. if (!isContinuation) { IEnumerable <object> itemsToRemove; if (this.EntityTrackingAdapter.MergeOption == MergeOption.OverwriteChanges) { itemsToRemove = linkedItemsInCollection.Select(i => i.Target); } else { Debug.Assert( this.EntityTrackingAdapter.MergeOption == MergeOption.PreserveChanges, "this.EntityTrackingAdapter.MergeOption == MergeOption.PreserveChanges"); itemsToRemove = linkedItemsInCollection .Where(i => !i.IsModified) .Select(i => i.Target); } itemsToRemove = itemsToRemove.Except(itemsEnumerable); foreach (var item in itemsToRemove) { if (collection != null) { property.RemoveValue(collection, item); } this.EntityTrackingAdapter.MaterializationLog.RemovedLink(entry, property.PropertyName, item); } } } }