Entities deep diff
$ dotnet add package DeepDiffFirst configure DeepDiff to know what types you want to compare, in the startup of your application
var diffConfiguration = new DiffConfiguration();
diffConfiguration.Entity<Entity>()
.HasKey(x => new { x.StartsOn, x.Name })
.HasValues(x => new { x.Price, x.Volume })
.HasMany(x => x.SubEntities)
.OnInsert(cfg => cfg.SetValue(x => x.PersistChange, PersistChange.Insert))
.OnUpdate(cfg => cfg.SetValue(x => x.PersistChange, PersistChange.Update))
.OnDelete(cfg => cfg.SetValue(x => x.PersistChange, PersistChange.Delete));
diffConfiguration.Entity<SubEntity>()
.HasKey(x => x.SubName)
.HasValues(x => x.Energy)
.OnInsert(cfg => cfg.SetValue(x => x.PersistChange, PersistChange.Insert))
.OnUpdate(cfg => cfg.SetValue(x => x.PersistChange, PersistChange.Update))
.OnDelete(cfg => cfg.SetValue(x => x.PersistChange, PersistChange.Delete))
var deepDiff = diffConfiguration.CreateDeepDiff();
Then in your application code, this will detect insert/update/delete between existing and new entities. In case of update, properties will be copied from new to existing entity
var result = deepDiff.MergeMany(existingEntities, newEntities); // result.Entities will contain 'diff' entities
Sample entities definition
public class Entity
{
public Guid Id { get; set; } // DB Key
public DateTime StartsOn { get; set; } // Business Key
public string Name { get; set; } // Business Key
public decimal Price { get; set; }
public int Volume { get; set; }
public PersistChange PersistChange { get; set; }
public List<SubEntity> SubEntities { get; set; }
}
public class SubEntity
{
public Guid Id { get; set; } // DB Key
public string SubName { get; set; } // Business Key
public int Energy { get; set; }
public PersistChange PersistChange { get; set; }
public Guid EntityId { get; set; } // Foreign Key
}
public enum PersistChange
{
None,
Inserted,
Updated,
Deleted
}
Defines properties used to compare and detect an insert and a delete. Mandatory unless NoKey has been defined
IEntityConfiguration<TEntity> HasKey<TKey>(Expression<Func<TEntity, TKey>> keyExpression)
IEntityConfiguration<TEntity> HasKey<TKey>(Expression<Func<TEntity, TKey>> keyExpression, Action<IKeyConfiguration<TEntity>> keyConfigurationAction)
Defines properties used to detect an update in case keys are identical
IEntityConfiguration<TEntity> HasValues<TValue>(Expression<Func<TEntity, TValue>> valuesExpression)
IEntityConfiguration<TEntity> HasValues<TValue>(Expression<Func<TEntity, TValue>> valuesExpression, Action<IValuesConfiguration<TEntity>> valuesConfigurationAction)Defines property to navigate to a single child
IEntityConfiguration<TEntity> HasOne<TChildEntity>(Expression<Func<TEntity, TChildEntity>> navigationPropertyExpression)
IEntityConfiguration<TEntity> HasOne<TChildEntity>(Expression<Func<TEntity, TChildEntity>> navigationPropertyExpression, Action<INavigationOneConfiguration<TEntity, TChildEntity>> navigationOneConfigurationAction)Defines property to navigation to multiple children
IEntityConfiguration<TEntity> HasMany<TChildEntity>(Expression<Func<TEntity, List<TChildEntity>>> navigationPropertyExpression)
IEntityConfiguration<TEntity> HasMany<TChildEntity>(Expression<Func<TEntity, List<TChildEntity>>> navigationPropertyExpression, Action<INavigationManyConfiguration<TEntity, TChildEntity>> navigationManyConfigurationAction)When set to true, engine will use force comparison by type if children are inherited and children collection is not abstract
INavigationManyConfiguration<TEntity, TChildEntity> UseDerivedTypes(bool use = false)Defines operations to perform when an insert is detected
IEntityConfiguration<TEntity> OnInsert(Action<IInsertConfiguration<TEntity>> insertConfigurationAction)When an insert is detected, overwrite a property with a specific value
IInsertConfiguration<TEntity> SetValue<TMember>(Expression<Func<TEntity, TMember>> destinationMember, TMember value)Defines operations to perform when an insert is detected. Properties specified in Values(...) will automatically be copied from new entity to existing one
IEntityConfiguration<TEntity> OnUpdate(Action<IUpdateConfiguration<TEntity>> updateConfigurationAction)When an update is detected, overwrite a property with a specific value
IUpdateConfiguration<TEntity> SetValue<TMember>(Expression<Func<TEntity, TMember>> destinationMember, TMember value)When an update is detected, specify additional properties to copy from new entity to existing one
IUpdateConfiguration<TEntity> CopyValues<TValue>(Expression<Func<TEntity, TValue>> copyValuesExpression)Defines operations to perform when a delete is detected.
IEntityConfiguration<TEntity> OnDelete(Action<IDeleteConfiguration<TEntity>> deleteConfigurationAction)When a delete is detected, overwrite property with a specific value
IDeleteConfiguration<TEntity> SetValue<TMember>(Expression<Func<TEntity, TMember>> destinationMember, TMember value)Defines the IEqualityComparer to use when comparing entity of that type
IEntityConfiguration<TEntity> WithComparer<T>(IEqualityComparer<T> equalityComparer)Defines additional criteria to detect an update even if Values are identical
IEntityConfiguration<TEntity> ForceUpdateIf(Action<IForceUpdateIfConfiguration<TEntity>> forceUpdateIfConfigurationAction)Trigger an update when a nested entity is modified
IForceUpdateIfConfiguration<TEntity> NestedEntitiesModified()Trigger an update when an equality condition is set
IForceUpdateIfConfiguration<TEntity> Equals<TMember>(Expression<Func<TEntity, TMember>> compareToMember, TMember compareToValue)Defines entity properties which will not be found anywhere in the entity diff configuration. This will be used by ValidateIfEveryPropertiesAreReferenced
IEntityConfiguration<TEntity> Ignore<TIgnore>(Expression<Func<TEntity, TIgnore>> ignoreExpression)Defines a no key entity, only update will be deteted for this kind of entity. Mandatory if no HasKey has been defined
IEntityConfiguration<TEntity> NoKey()MergeSingleResult<TEntity> MergeSingle<TEntity>(TEntity existingEntity, TEntity newEntity)
MergeSingleResult<TEntity> MergeSingle<TEntity>(TEntity existingEntity, TEntity newEntity, Action<IMergeSingleConfiguration> mergeSingleConfigurationAction)MergeManyResult<TEntity> MergeMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities)
MergeManyResult<TEntity> MergeMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities, Action<IMergeManyConfiguration> mergeManyConfigurationAction)IReadOnlyCollection<DiffOperationBase> DiffSingle<TEntity>(TEntity existingEntity, TEntity newEntity);
IReadOnlyCollection<DiffOperationBase> DiffSingle<TEntity>(TEntity existingEntity, TEntity newEntity, Action<IDiffSingleConfiguration> diffSingleConfigurationAction);IReadOnlyCollection<DiffOperationBase> DiffMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities);
IReadOnlyCollection<DiffOperationBase> DiffMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities, Action<IDiffManyConfiguration> diffManyConfigurationAction);When set to true, hashtable will be used when searching in a collection of entities with a minimum HashtableThreshold (15 by default) entries (true by default)
IMergeSingleConfiguration UseHashtable(bool use = true)Defines minimum number of entries in collection to use hashtable (15 by default)
IMergeSingleConfiguration HashtableThreshold(int threshold = 15)Force OnUpdate to be triggered if a nested entity has been modified even if current entity is not modified
IMergeSingleConfiguration ForceOnUpdateEvenIfModificationsDetectedOnlyInNestedLevel(bool force = false)DiffOperations values (flags) None Insert Delete Update = UpdateValue | UpdateSetValue | UpdateCopyValue All = Insert | Delete | Update Engine will generate a collection of operations for selected DiffOperations values detected when performing diff (None by default)
IMergeSingleConfiguration GenerateOperations(DiffOperations operationsToGenerate = DiffOperations.None)When set to true, engine will use optimized equality comparers to compare keys and values (true by default)
IMergeSingleConfiguration UsePrecompiledEqualityComparer(bool use = true)When set to true, hashtable will be used when searching in a collection of entities with a minimum HashtableThreshold (15 by default) entries (true by default)
IMergeManyConfiguration UseHashtable(bool use = true)Defines minimum number of entries in collection to use hashtable (15 by default)
IMergeManyConfiguration HashtableThreshold(int threshold = 15)Force OnUpdate to be triggered if a nested entity has been modified even if current entity is not modified
IMergeManyConfiguration ForceOnUpdateEvenIfModificationsDetectedOnlyInNestedLevel(bool force = false)DiffOperations values (flags) None Insert Delete Update = UpdateValue | UpdateSetValue | UpdateCopyValue All = Insert | Delete | Update Engine will generate a collection of operations for selected DiffOperations values detected when performing diff (None by default)
IMergeManyConfiguration GenerateOperations(DiffOperations operationsToGenerate = DiffOperations.None)When set to true, engine will use optimized equality comparers to compare keys and values (true by default)
IMergeManyConfiguration UsePrecompiledEqualityComparer(bool use = true)When set to true, hashtable will be used when searching in a collection of entities with a minimum HashtableThreshold (15 by default) entries (true by default)
IDiffSingleConfiguration UseHashtable(bool use = true);Defines minimum number of entries in collection to use hashtable (15 by default)
IDiffSingleConfiguration HashtableThreshold(int threshold = 15);When set to true, engine will use optimized equality comparers to compare keys and values (true by default)
IDiffSingleConfiguration UsePrecompiledEqualityComparer(bool use = true);DiffOperations values (flags) None Insert Delete Update = UpdateValue | UpdateSetValue | UpdateCopyValue All = Insert | Delete | Update Engine will generate a collection of operations for selected DiffOperations values detected when performing diff (All by default)
IDiffSingleConfiguration GenerateOperations(DiffOperations operationsToGenerate = DiffOperations.All);When set to true, hashtable will be used when searching in a collection of entities with a minimum HashtableThreshold (15 by default) entries (true by default)
IDiffManyConfiguration UseHashtable(bool use = true);Defines minimum number of entries in collection to use hashtable (15 by default)
IDiffManyConfiguration HashtableThreshold(int threshold = 15);When set to true, engine will use optimized equality comparers to compare keys and values (true by default)
IDiffManyConfiguration UsePrecompiledEqualityComparer(bool use = true);DiffOperations values (flags) None Insert Delete Update = UpdateValue | UpdateSetValue | UpdateCopyValue All = Insert | Delete | Update Engine will generate a collection of operations for selected DiffOperations values detected when performing diff (All by default)
IDiffManyConfiguration GenerateOperations(DiffOperations operationsToGenerate = DiffOperations.All);Create an entity configuration
IEntityConfiguration<TEntity> Entity<TEntity>()Add diff profile
IDeepDiffConfiguration AddProfile<TProfile>()
IDeepDiffConfiguration AddProfile(DiffProfile diffProfile)Scan assemblies and add diff profile found in those assemblies
IDeepDiffConfiguration AddProfiles(params Assembly[] assembliesToScan)Create DeepDiff engine (also validate configuration)
IDeepDiff CreateDeepDiff()Validate entity configurations
void ValidateConfiguration()Check if every properties found in configured entities are used in configuration, use Ignore to add properties to ignore in this validation
void ValidateIfEveryPropertiesAreReferenced()Keys of entity on which insert has been performed
Name of entity on which insert has been performed
Keys of entity on which update has been performed
Name of entity on which update has been performed
Collection of properties from Values configuration on which update has been performed
Collection of properties on which SetValue has been performed
Collection of properties on which CopyValues has been performed
Keys of entity on which delete has been performed
Name of entity on which delete has been performed