DeepDiff 1.12.0
dotnet add package DeepDiff --version 1.12.0
NuGet\Install-Package DeepDiff -Version 1.12.0
<PackageReference Include="DeepDiff" Version="1.12.0" />
<PackageVersion Include="DeepDiff" Version="1.12.0" />
<PackageReference Include="DeepDiff" />
paket add DeepDiff --version 1.12.0
#r "nuget: DeepDiff, 1.12.0"
#:package DeepDiff@1.12.0
#addin nuget:?package=DeepDiff&version=1.12.0
#tool nuget:?package=DeepDiff&version=1.12.0
Breaking changes
1.12.0
- Hashtable and PrecompiledComparer are now mandatory
1.11.1
- By default, DeepDiff will now check for duplicate keys in entities and nested entities. You can disable this behavior using SetCheckDuplicateKeys(false) in MergeSingle, MergeMany, CompareSingle and CompareMany configuration
1.11.0
- IOperationListener are now mandatory when using CompareSingle and CompareMany methods
1.10.0
- to configure an entity, you must now use the
ConfigureEntity<TEntity>()method instead ofEntity<TEntity>()
Example
How do I get started
First configure DeepDiff to register what types you want to compare, in the startup of your application
var diffConfiguration = new DiffConfiguration();
diffConfiguration.ConfigureEntity<Entity>() // configure Entity type
.HasKey(x => new { x.StartsOn, x.Name }) // business key
.HasValues(x => new { x.Price, x.Volume }) // properties to compare for update (and copy on update)
.HasMany(x => x.SubEntities) // one-to-many relation
.OnInsert(cfg => cfg // operations to perform on insert
.SetValue(x => x.PersistChange, PersistChange.Insert)) // change PersistChange property to Insert
.OnUpdate(cfg => cfg // operations to perform on update
.SetValue(x => x.PersistChange, PersistChange.Update)) // change PersistChange property to Update
.OnDelete(cfg => cfg // operations to perform on delete
.SetValue(x => x.PersistChange, PersistChange.Delete)); // change PersistChange property to Delete
diffConfiguration.ConfigureEntity<SubEntity>() // configure SubEntity type
.HasKey(x => x.SubName) // business key
.HasValues(x => x.Energy) // property to compare for update (and copy on update)
.OnInsert(cfg => cfg // operations to perform on insert
.SetValue(x => x.PersistChange, PersistChange.Insert)) // change PersistChange property to Insert
.OnUpdate(cfg => cfg // operations to perform on update
.SetValue(x => x.PersistChange, PersistChange.Update) // change PersistChange property to Update
.CopyValues(x => x.Description) // copy Description property from new to existing entity
.OnDelete(cfg => cfg // operations to perform on delete
.SetValue(x => x.PersistChange, PersistChange.Delete)) // change PersistChange property to Delete
.Ignore(x => new { x.Entity, x.EntityId} ); // foreign key and navigation are not relevant for diff
var deepDiff = diffConfiguration.CreateDeepDiff(); // finalize configuration
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. PersistChange property will be set accordingly, so you can persist changes in your database and in case of update Description property will also be copied from new to existing sub entity.
var resultEntities = deepDiff.MergeMany(existingEntities, newEntities); // resultEntities will contain 'merged' entities
Example 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 string Description { get; set; } // Not part of key or values, will not be used in diff
public PersistChange PersistChange { get; set; }
public Guid EntityId { get; set; } // Foreign Key
public Entity Entity { get; set; } // Navigation property
}
public enum PersistChange
{
None,
Insert,
Update,
Delete
}
Entity Configuration
HasKey
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)
HasValues
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)
HasOne
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)
HasMany
Defines property to navigate 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)
UseDerivedTypes
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)
OnInsert
Defines operations to perform when an insert is detected
IEntityConfiguration<TEntity> OnInsert(Action<IInsertConfiguration<TEntity>> insertConfigurationAction)
SetValue
When an insert is detected, overwrite a property with a specific value
IInsertConfiguration<TEntity> SetValue<TMember>(Expression<Func<TEntity, TMember>> destinationMember, TMember value)
OnUpdate
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)
SetValue
When an update is detected, overwrite a property with a specific value
IUpdateConfiguration<TEntity> SetValue<TMember>(Expression<Func<TEntity, TMember>> destinationMember, TMember value)
CopyValues
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)
OnDelete
Defines operations to perform when a delete is detected.
IEntityConfiguration<TEntity> OnDelete(Action<IDeleteConfiguration<TEntity>> deleteConfigurationAction)
SetValue
When a delete is detected, overwrite property with a specific value
IDeleteConfiguration<TEntity> SetValue<TMember>(Expression<Func<TEntity, TMember>> destinationMember, TMember value)
WithComparer
Defines the IEqualityComparer to use when comparing entity of that type
IEntityConfiguration<TEntity> WithComparer<T>(IEqualityComparer<T> equalityComparer)
ForceUpdateIf
Defines additional criteria to force an update even if no update is detected using entity value(s).
IEntityConfiguration<TEntity> ForceUpdateIf(Action<IForceUpdateIfConfiguration<TEntity>> forceUpdateIfConfigurationAction)
NestedEntitiesModified
Trigger an update when a nested entity is modified
IForceUpdateIfConfiguration<TEntity> NestedEntitiesModified()
Equals
Trigger an update when an equality condition is met
IForceUpdateIfConfiguration<TEntity> Equals<TMember>(Expression<Func<TEntity, TMember>> compareToMember, TMember compareToValue)
Ignore
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)
NoKey
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()
Engine configuration
MergeSingle
TEntity MergeSingle<TEntity>(TEntity existingEntity, TEntity newEntity)
TEntity MergeSingle<TEntity>(TEntity existingEntity, TEntity newEntity, IOperationListener operationListener)
TEntity MergeSingle<TEntity>(TEntity existingEntity, TEntity newEntity, Action<IMergeSingleConfiguration> mergeSingleConfigurationAction)
TEntity MergeSingle<TEntity>(TEntity existingEntity, TEntity newEntity, IOperationListener operationListener, Action<IMergeSingleConfiguration> mergeSingleConfigurationAction)
MergeMany
IEnumerable<TEntity> MergeMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities)
IEnumerable<TEntity> MergeMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities, IOperationListener operationListener)
IEnumerable<TEntity> MergeMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities, Action<IMergeManyConfiguration> mergeManyConfigurationAction)
IEnumerable<TEntity> MergeMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities, IOperationListener operationListener, Action<IMergeManyConfiguration> mergeManyConfigurationAction)
CompareSingle
void CompareSingle<TEntity>(TEntity existingEntity, TEntity newEntity, IOperationListener operationListener);
void CompareSingle<TEntity>(TEntity existingEntity, TEntity newEntity, IOperationListener operationListener, Action<ICompareSingleConfiguration> compareSingleConfigurationAction);
CompareMany
void CompareMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities, IOperationListener operationListener);
void CompareMany<TEntity>(IEnumerable<TEntity> existingEntities, IEnumerable<TEntity> newEntities, IOperationListener operationListener, Action<ICompareManyConfiguration> compareManyConfigurationAction);
MergeSingle configuration
HashtableThreshold
Defines minimum number of entries in collection to use hashtable (15 by default)
IMergeSingleConfiguration HashtableThreshold(int threshold = 15)
ForceOnUpdateWhenModificationsDetectedOnlyInNestedLevel
Force OnUpdate to be triggered if a nested entity has been modified even if current entity is not modified (false by default))
IMergeSingleConfiguration ForceOnUpdateWhenModificationsDetectedOnlyInNestedLevel(bool force = false)
SetCheckDuplicateKeys
Indicates whether to check for duplicate keys in entities or nested entities (true by default).
IMergeSingleConfiguration SetCheckDuplicateKeys(bool checkDuplicateKeys = true)
MergeMany configuration
HashtableThreshold
Defines minimum number of entries in collection to use hashtable (15 by default)
IMergeManyConfiguration HashtableThreshold(int threshold = 15)
ForceOnUpdateWhenModificationsDetectedOnlyInNestedLevel
Force OnUpdate to be triggered if a nested entity has been modified even if current entity is not modified
IMergeManyConfiguration ForceOnUpdateWhenModificationsDetectedOnlyInNestedLevel(bool force = false)
SetCheckDuplicateKeys
Indicates whether to check for duplicate keys in entities or nested entities (true by default).
IMergeManyConfiguration SetCheckDuplicateKeys(bool checkDuplicateKeys = true)
CompareSingle configuration
HashtableThreshold
Defines minimum number of entries in collection to use hashtable (15 by default)
ICompareSingleConfiguration HashtableThreshold(int threshold = 15);
SetCheckDuplicateKeys
Indicates whether to check for duplicate keys in entities or nested entities (true by default).
ICompareSingleConfiguration SetCheckDuplicateKeys(bool checkDuplicateKeys = true)
CompareMany configuration
HashtableThreshold
Defines minimum number of entries in collection to use hashtable (15 by default)
ICompareManyConfiguration HashtableThreshold(int threshold = 15);
SetCheckDuplicateKeys
Indicates whether to check for duplicate keys in entities or nested entities (true by default).
ICompareManyConfiguration SetCheckDuplicateKeys(bool checkDuplicateKeys = true)
OperationListener
Defines a listener which will be called on every insert/update/delete detection
OnInsert
void OnDelete(string entityTypeName, Func<Dictionary<string, object>> getKeysFunc, Func<Dictionary<string, Dictionary<string, object>>> getNavigationParentKeysFunc);
OnDelete
void OnInsert(string entityTypeName, Func<Dictionary<string, object>> getKeysFunc, Func<Dictionary<string, Dictionary<string, object>>> getNavigationParentKeysFunc);
OnUpdate
void OnUpdate(string entityTypeName, string propertyName, Func<Dictionary<string, object>> getKeysFunc, Func<object> getOriginalValueFunc, Func<Dictionary<string, Dictionary<string, object>>> getNavigationParentKeysFunc);
Deep Diff Configuration
ConfigureEntity
Create an entity configuration
IEntityConfiguration<TEntity> ConfigureEntity<TEntity>()
AddProfile
Add diff profile
IDeepDiffConfiguration AddProfile<TProfile>()
IDeepDiffConfiguration AddProfile(DiffProfile diffProfile)
AddProfiles
Scan assemblies and add diff profile found in those assemblies
IDeepDiffConfiguration AddProfiles(params Assembly[] assembliesToScan)
CreateDeepDiff
Create DeepDiff engine (also validate configuration)
IDeepDiff CreateDeepDiff()
ValidateConfiguration
Validate entity configurations
void ValidateConfiguration()
ValidateIfEveryPropertiesAreReferenced
Check if every properties found in configured entities are used in configuration, use Ignore to add properties to ignore in this validation
void ValidateIfEveryPropertiesAreReferenced()
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 is compatible. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net5.0
- No dependencies.
-
net6.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on DeepDiff:
| Package | Downloads |
|---|---|
|
DeepDiff.Extensions.Microsoft.DependencyInjection
DeepDeef extensions for Microsft Dependendy Injection |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.12.0 | 169 | 11/2/2025 |
| 1.11.0 | 174 | 9/24/2025 |
| 1.10.1 | 266 | 5/7/2025 |
| 1.10.0 | 184 | 4/11/2025 |
| 1.9.5 | 219 | 4/7/2025 |
| 1.9.4 | 219 | 4/7/2025 |
| 1.9.3 | 149 | 4/5/2025 |
| 1.9.2 | 169 | 4/4/2025 |
| 1.9.1 | 206 | 3/13/2025 |
| 1.9.0 | 281 | 3/4/2025 |
| 1.8.9 | 156 | 2/26/2025 |
| 1.8.8 | 148 | 2/26/2025 |
| 1.8.7 | 154 | 2/25/2025 |
| 1.8.6 | 156 | 2/25/2025 |
| 1.8.5 | 150 | 1/22/2025 |
| 1.8.4 | 158 | 1/21/2025 |
| 1.8.3 | 153 | 1/8/2025 |
| 1.8.2 | 198 | 7/2/2024 |
| 1.8.1 | 180 | 6/27/2024 |
| 1.8.0 | 170 | 6/21/2024 |
| 1.7.0 | 199 | 4/30/2024 |
| 1.6.4 | 183 | 4/26/2024 |
| 1.6.3 | 193 | 3/15/2024 |
| 1.6.2 | 174 | 2/27/2024 |
| 1.6.1 | 183 | 2/26/2024 |
| 1.6.0 | 169 | 2/22/2024 |
| 1.5.1 | 206 | 2/14/2024 |
| 1.5.0 | 557 | 1/31/2024 |
| 1.4.2 | 152 | 1/30/2024 |
| 1.4.1 | 165 | 1/30/2024 |
| 1.4.0 | 173 | 1/29/2024 |
| 1.3.6 | 178 | 1/27/2024 |
| 1.3.5 | 168 | 1/26/2024 |
| 1.3.4 | 163 | 1/26/2024 |
| 1.3.3 | 212 | 1/26/2024 |
| 1.3.2 | 163 | 1/25/2024 |
| 1.3.1 | 174 | 1/24/2024 |
| 1.3.0 | 166 | 1/24/2024 |
| 1.2.3 | 173 | 1/18/2024 |
| 1.2.2 | 186 | 1/9/2024 |
| 1.2.1 | 218 | 12/15/2023 |
| 1.1.1 | 183 | 12/7/2023 |
| 1.1.0 | 254 | 12/4/2023 |
| 1.0.2 | 241 | 12/2/2023 |
| 1.0.1 | 239 | 12/1/2023 |
| 1.0.0 | 182 | 12/1/2023 |