mirror of https://github.com/abpframework/abp.git
4 changed files with 128 additions and 11 deletions
@ -0,0 +1,26 @@ |
|||
using Microsoft.EntityFrameworkCore.Metadata.Builders; |
|||
using Volo.Abp.EntityFrameworkCore.ValueComparers; |
|||
using Volo.Abp.EntityFrameworkCore.ValueConverters; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.Modeling; |
|||
|
|||
public static class AbpPropertyBuilderExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Stores the property as a JSON serialized string with snapshot-based
|
|||
/// change tracking.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// A fallback for EF Core providers without owned-JSON (ToJson) or primitive
|
|||
/// collection mapping support. The value is converted as a whole: JSON path
|
|||
/// querying and partial updates are not available, and the property type must
|
|||
/// fully round-trip with System.Text.Json.
|
|||
/// </remarks>
|
|||
public static PropertyBuilder<TProperty> HasAbpJsonConversion<TProperty>( |
|||
this PropertyBuilder<TProperty> propertyBuilder) |
|||
{ |
|||
return propertyBuilder.HasConversion( |
|||
new AbpJsonValueConverter<TProperty>(), |
|||
new AbpJsonValueComparer<TProperty>()); |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using System.Text.Json; |
|||
using Microsoft.EntityFrameworkCore.ChangeTracking; |
|||
using Volo.Abp.EntityFrameworkCore.ValueConverters; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.ValueComparers; |
|||
|
|||
public class AbpJsonValueComparer<TPropertyType> : ValueComparer<TPropertyType> |
|||
{ |
|||
public AbpJsonValueComparer() |
|||
: base( |
|||
(left, right) => Serialize(left) == Serialize(right), |
|||
v => Serialize(v).GetHashCode(), |
|||
v => Deserialize(Serialize(v))) |
|||
{ |
|||
} |
|||
|
|||
private static string Serialize(TPropertyType? value) |
|||
{ |
|||
return JsonSerializer.Serialize(value, AbpJsonValueConverter<TPropertyType>.SerializeOptions); |
|||
} |
|||
|
|||
private static TPropertyType Deserialize(string value) |
|||
{ |
|||
return JsonSerializer.Deserialize<TPropertyType>(value, AbpJsonValueConverter<TPropertyType>.DeserializeOptions)!; |
|||
} |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
using System.Collections.Generic; |
|||
using Shouldly; |
|||
using Volo.Abp.EntityFrameworkCore.ValueComparers; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.ValueComparers; |
|||
|
|||
public class AbpJsonValueComparer_Tests |
|||
{ |
|||
[Fact] |
|||
public void Should_Compare_Collections_By_Content() |
|||
{ |
|||
var comparer = new AbpJsonValueComparer<List<string>>(); |
|||
|
|||
comparer.Equals(new List<string> { "a", "b" }, new List<string> { "a", "b" }).ShouldBeTrue(); |
|||
comparer.Equals(new List<string> { "a", "b" }, new List<string> { "b", "a" }).ShouldBeFalse(); |
|||
comparer.GetHashCode(new List<string> { "a", "b" }) |
|||
.ShouldBe(comparer.GetHashCode(new List<string> { "a", "b" })); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Handle_Null_Values() |
|||
{ |
|||
var comparer = new AbpJsonValueComparer<List<string>>(); |
|||
|
|||
comparer.Equals(null, null).ShouldBeTrue(); |
|||
comparer.Equals(new List<string>(), null).ShouldBeFalse(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Snapshot_Should_Be_A_Deep_Copy() |
|||
{ |
|||
var comparer = new AbpJsonValueComparer<List<string>>(); |
|||
var original = new List<string> { "a" }; |
|||
|
|||
var snapshot = (List<string>)comparer.Snapshot(original)!; |
|||
original.Add("b"); |
|||
|
|||
snapshot.ShouldBe(new[] { "a" }); |
|||
comparer.Equals(original, snapshot).ShouldBeFalse(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Snapshot_Should_Copy_Nested_Arrays_Of_Typed_Objects() |
|||
{ |
|||
var comparer = new AbpJsonValueComparer<SampleData>(); |
|||
var original = new SampleData { Count = 1, Tags = new[] { "x" } }; |
|||
|
|||
var snapshot = (SampleData)comparer.Snapshot(original)!; |
|||
original.Tags[0] = "changed"; |
|||
original.Count = 2; |
|||
|
|||
snapshot.Tags.ShouldBe(new[] { "x" }); |
|||
snapshot.Count.ShouldBe(1); |
|||
comparer.Equals(original, snapshot).ShouldBeFalse(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Support_Nullable_Value_Types() |
|||
{ |
|||
var comparer = new AbpJsonValueComparer<int?>(); |
|||
|
|||
comparer.Equals(42, 42).ShouldBeTrue(); |
|||
comparer.Equals(42, 43).ShouldBeFalse(); |
|||
comparer.Equals(null, null).ShouldBeTrue(); |
|||
} |
|||
|
|||
private class SampleData |
|||
{ |
|||
public int Count { get; set; } |
|||
|
|||
public string[] Tags { get; set; } = default!; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue