From be6a08ab4cacfce97a9ca097af7f1186d410328d Mon Sep 17 00:00:00 2001 From: Felix-CodingClimber Date: Tue, 2 Apr 2024 22:20:31 +0200 Subject: [PATCH] Added ef core json columns helper extension. Addded todo comments to repository. --- .../Extensions/PropertyBuilderExtensions.cs | 40 +++++++++++++++++++ .../Core/ReadOnlyRepository.cs | 1 + src/DotNetElements.Core/Core/Repository.cs | 1 + 3 files changed, 42 insertions(+) create mode 100644 src/DotNetElements.Core/Core/Extensions/PropertyBuilderExtensions.cs diff --git a/src/DotNetElements.Core/Core/Extensions/PropertyBuilderExtensions.cs b/src/DotNetElements.Core/Core/Extensions/PropertyBuilderExtensions.cs new file mode 100644 index 0000000..38b3b66 --- /dev/null +++ b/src/DotNetElements.Core/Core/Extensions/PropertyBuilderExtensions.cs @@ -0,0 +1,40 @@ +using System.Text.Json; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace DotNetElements.Core.Extensions; + +public static class PropertyBuilderExtensions +{ + public static PropertyBuilder HasJsonConversion(this PropertyBuilder propertyBuilder) where T : class, new() + { + JsonSerializerOptions options = new() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true, // todo check if we want to make that a parameter (might make sense to only use it in debug/test builds) + AllowTrailingCommas = true, + PropertyNameCaseInsensitive = true + }; + + ValueConverter converter = new ValueConverter + ( + value => JsonSerializer.Serialize(value, options), + value => JsonSerializer.Deserialize(value, options) ?? new T() + ); + + ValueComparer comparer = new ValueComparer + ( + (valueA, valueB) => JsonSerializer.Serialize(valueA, options) == JsonSerializer.Serialize(valueB, options), + value => value == null ? 0 : JsonSerializer.Serialize(value, options).GetHashCode(), + value => JsonSerializer.Deserialize(JsonSerializer.Serialize(value, options), options) + ); + + propertyBuilder.HasConversion(converter); + propertyBuilder.Metadata.SetValueConverter(converter); + propertyBuilder.Metadata.SetValueComparer(comparer); + propertyBuilder.HasColumnType("nvarchar(max)"); + + return propertyBuilder; + } +} diff --git a/src/DotNetElements.Core/Core/ReadOnlyRepository.cs b/src/DotNetElements.Core/Core/ReadOnlyRepository.cs index a6a8e06..7bcc377 100644 --- a/src/DotNetElements.Core/Core/ReadOnlyRepository.cs +++ b/src/DotNetElements.Core/Core/ReadOnlyRepository.cs @@ -63,6 +63,7 @@ public async Task> GetFilteredWithProjectionAsync> GetByIdWithProjectionAsync( TKey id, Expression, IQueryable>> selector, diff --git a/src/DotNetElements.Core/Core/Repository.cs b/src/DotNetElements.Core/Core/Repository.cs index d872a39..c0ce282 100644 --- a/src/DotNetElements.Core/Core/Repository.cs +++ b/src/DotNetElements.Core/Core/Repository.cs @@ -175,6 +175,7 @@ public virtual async Task ClearTable() } // todo protected would be better! + // todo check if we should make checkAlreadyTracked true by default public TRelatedEntity AttachById(TRelatedEntityKey id, bool checkAlreadyTracked = false) where TRelatedEntity : Entity, IRelatedEntity where TRelatedEntityKey : notnull, IEquatable