diff --git a/src/XrmFramework/Extensions/BindingModelExtensions.cs b/src/XrmFramework/Extensions/BindingModelExtensions.cs index 5de69d98..d58661eb 100644 --- a/src/XrmFramework/Extensions/BindingModelExtensions.cs +++ b/src/XrmFramework/Extensions/BindingModelExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Christophe Gondouin (CGO Conseils). All rights reserved. +// Copyright (c) Christophe Gondouin (CGO Conseils). All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using System; @@ -15,38 +15,36 @@ public static class BindingModelExtensions { public static T GetDiffGeneric(this T source, T target) where T : IBindingModel, new() - { - return (T)GetDiff(source, target); - } + => (T)GetDiff(source, target); - public static IEnumerable GetDiff(this IEnumerable sourceList, IEnumerable targetEnumerable, IEqualityComparer comparer = null) where T : IBindingModel - { - return GetDiff(sourceList.Cast(), targetEnumerable.Cast(), typeof(T), comparer); - } + public static IEnumerable GetDiffGeneric(this IEnumerable sourceList, IEnumerable targetEnumerable, IEqualityComparer comparer = null) where T : IBindingModel, new() + => sourceList.GetDiff(targetEnumerable, comparer); - public static IEnumerable GetDiff(this IEnumerable sourceList, IEnumerable targetEnumerable, Type modelType, IEqualityComparer comparer = null) + private static IEnumerable GetDiff(this IEnumerable sourceList, IEnumerable targetEnumerable, IEqualityComparer comparer = null) where T : IBindingModel + => GetDiff(sourceList.Cast(), targetEnumerable.Cast(), typeof(T), comparer).Cast(); + + private static IEnumerable GetDiff(this IEnumerable sourceList, IEnumerable targetEnumerable, Type modelType, IEqualityComparer comparer = null) { - var metadata = EntityMetadata.GetMetadata(modelType); + comparer ??= new KeyEqualityComparer(modelType); - comparer = comparer ?? new KeyEqualityComparer(modelType); + var targetList = targetEnumerable.ToList(); - var targetList = targetEnumerable as IList ?? targetEnumerable.ToList(); - var objectsToUpsert = sourceList.Except(targetList, new DeepModelEqualityComparer(modelType)); + var sourceBindingModels = sourceList.ToList(); + var objectsToUpsert = sourceBindingModels.Except(targetList, new DeepModelEqualityComparer(modelType)); - foreach (var obj in objectsToUpsert) - { - var existingObject = targetList.SingleOrDefault(o => comparer.Equals(obj, o)); + var objectsToUpdate = + objectsToUpsert + .Join( + targetList, o => o, o => o, + (obj, existingObject) => + GetDiff(obj, existingObject), comparer); - if (!metadata.IsValidForCreate && existingObject == null) - { - continue; - } + var objectsToCreate = sourceBindingModels.Except(targetList, comparer); - yield return existingObject == null ? obj : GetDiff(obj, existingObject); - } + return objectsToUpdate.Union(objectsToCreate); } - public static IBindingModel GetDiff(this IBindingModel source, IBindingModel target) + private static IBindingModel GetDiff(this IBindingModel source, IBindingModel target) { if (target == null) { @@ -68,12 +66,9 @@ public static IBindingModel GetDiff(this IBindingModel source, IBindingModel tar foreach (var attribute in metadata.CrmAttributes.Where(a => a.CrmMapping.IsValidForUpdate)) { - if (source is BindingModelBase) + if (source is BindingModelBase @base && !@base.InitializedProperties.Contains(attribute.PropertyName)) { - if (!((BindingModelBase)source).InitializedProperties.Contains(attribute.PropertyName)) - { - continue; - } + continue; } var valueSource = attribute.Property.GetValue(source); @@ -140,7 +135,7 @@ public static void CopyField(this TInput input, TOutput output, private static void CopyFieldInternal(TInput input, TOutput output, PropertyInfo sourceProperty, PropertyInfo targetProperty, Type converterType) where TInput : BindingModelBase where TOutput : IBindingModel { - if (sourceProperty == null || targetProperty == null || input.InitializedProperties.Contains(sourceProperty.Name) == false) + if (sourceProperty == null || targetProperty == null || !input.InitializedProperties.Contains(sourceProperty.Name)) { return; } @@ -166,7 +161,7 @@ private static void CopyFieldInternal(TInput input, TOutput out foreach (var element in (IEnumerable)sourceValue) { - addMethod?.Invoke(collection, new[] { element }); + addMethod.Invoke(collection, new[] { element }); } } else @@ -191,23 +186,23 @@ private static PropertyInfo GetPropertyInfo(Expression> prope public class KeyEqualityComparer : IEqualityComparer { - private PropertyInfo PropertyInfo { get; } - private EntityMetadata Metadata { get; } private bool HasPreferedKey { get; } + internal IEnumerable Properties { get; } public KeyEqualityComparer(Type modelType) { Metadata = EntityMetadata.GetMetadata(modelType); HasPreferedKey = Metadata.HasPreferedKey; + Properties = Metadata.CrmAttributes.Where(a => (a.IsKey && !HasPreferedKey) || (HasPreferedKey && a.IsPreferedKey)); } public bool Equals(IBindingModel x, IBindingModel y) { var equals = true; - foreach (var attributeMetada in Metadata.CrmAttributes.Where(a => (a.IsKey && !HasPreferedKey) || (HasPreferedKey && a.IsPreferedKey))) + foreach (var attributeMetada in Properties) { var valueX = attributeMetada.Property.GetValue(x); var valueY = attributeMetada.Property.GetValue(y); @@ -228,9 +223,8 @@ public int GetHashCode(IBindingModel obj) { int hashCode = 0; - foreach (var attributeMetada in Metadata.CrmAttributes.Where(a => (a.IsKey && !HasPreferedKey) || (HasPreferedKey && a.IsPreferedKey))) + foreach (var attributeMetada in Properties) { - hashCode ^= attributeMetada.Property.GetValue(obj)?.GetHashCode() ?? 0; } return hashCode; @@ -302,7 +296,7 @@ public class ModelEqualityComparer : IEqualityComparer where T : IBindingM { public bool Equals(T x, T y) { - return x.Id == y.Id; + return x?.Id == y?.Id; } public int GetHashCode(T obj) @@ -313,8 +307,6 @@ public int GetHashCode(T obj) public class DeepModelEqualityComparer : IEqualityComparer { - //private IList Properties { get; set; } - private EntityMetadata Metadata { get; } public DeepModelEqualityComparer(Type modelType)