From 3eaeb19a2bd868829510e96a2c80d82164e0da66 Mon Sep 17 00:00:00 2001 From: Jakub Berthoty Date: Thu, 21 Nov 2019 15:09:17 +0100 Subject: [PATCH 1/2] Add JsonConverter for converting entity to/from JSON --- src/Converters/JsonConverter.cs | 47 +++++++++ src/Kros.KORM.Extensions.Asp.csproj | 1 + tests/Converters/JsonConverterShould.cs | 127 ++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 src/Converters/JsonConverter.cs create mode 100644 tests/Converters/JsonConverterShould.cs diff --git a/src/Converters/JsonConverter.cs b/src/Converters/JsonConverter.cs new file mode 100644 index 0000000..13fff37 --- /dev/null +++ b/src/Converters/JsonConverter.cs @@ -0,0 +1,47 @@ +using Kros.Utils; +using System; +using System.Text.Json; + +namespace Kros.KORM.Converter +{ + /// + /// Converter for converting JSON value from DB to entity. + /// + /// + public class JsonConverter : IConverter + { + private readonly JsonSerializerOptions _options; + + /// + /// Initializes a new instance of the class with default serialization options. + /// + public JsonConverter() : this(new JsonSerializerOptions()) + { } + + /// + /// Initializes a new instance of the class. + /// + /// Serialization options. + /// The value of is null. + public JsonConverter(JsonSerializerOptions options) + { + _options = Check.NotNull(options, nameof(options)); + } + + /// + /// Converts specified JSON value from DB to entity. + /// + /// JSON value. + /// Entity. + public object Convert(object value) + => JsonSerializer.Deserialize((string)value, typeof(T), _options); + + /// + /// Converts entity to JSON value for DB. + /// + /// Entity. + /// Converted JSON value for DB. + public object ConvertBack(object value) + => JsonSerializer.Serialize(value, typeof(T), _options); + } +} diff --git a/src/Kros.KORM.Extensions.Asp.csproj b/src/Kros.KORM.Extensions.Asp.csproj index 0558213..08cd877 100644 --- a/src/Kros.KORM.Extensions.Asp.csproj +++ b/src/Kros.KORM.Extensions.Asp.csproj @@ -37,6 +37,7 @@ + diff --git a/tests/Converters/JsonConverterShould.cs b/tests/Converters/JsonConverterShould.cs new file mode 100644 index 0000000..c16bd8c --- /dev/null +++ b/tests/Converters/JsonConverterShould.cs @@ -0,0 +1,127 @@ +using FluentAssertions; +using Kros.KORM.Converter; +using System; +using System.Text.Json; +using System.Text.RegularExpressions; +using Xunit; + +namespace Kros.KORM.Extensions.Api.UnitTests.Converters +{ + public class JsonConverterShould + { + [Fact] + public void ThrowArgumentExceptionWhenSerializationOptionsAreNull() + { + Action action = () => new JsonConverter(null); + + action.Should().Throw(); + } + + [Fact] + public void ConvertJsonToEntity() + { + var converter = new JsonConverter(); + + TestClass expected = GetSampleClass(); + var actual = converter.Convert(GetSampleJson()); + + actual.Should().BeOfType(typeof(TestClass)); + ((TestClass)actual).Should().BeEquivalentTo(expected); + } + + [Fact] + public void ThrowJsonExceptionWhenTryingToConvertImproperlyFormattedJsonToEntity() + { + var converter = new JsonConverter(); + + Action action = () => converter.Convert(GetSampleImproperlyFormattedJson()); + + action.Should().Throw(); + } + + [Fact] + public void ConvertImproperlyFormattedJsonToEntityWhenUsingCorrectOptions() + { + var converter = new JsonConverter(new JsonSerializerOptions() + { + AllowTrailingCommas = true, + PropertyNameCaseInsensitive = true + }); + + TestClass expected = GetSampleClass(); + var actual = converter.Convert(GetSampleImproperlyFormattedJson()); + + actual.Should().BeOfType(typeof(TestClass)); + ((TestClass)actual).Should().BeEquivalentTo(expected); + } + + [Fact] + public void ConvertEntityToJson() + { + var converter = new JsonConverter(); + + string expected = GetSampleJson(); + var actual = converter.ConvertBack(GetSampleClass()); + + actual.Should().BeOfType(typeof(string)); + ((string)actual).Should().Equals(expected); + } + + private TestClass GetSampleClass() + => new TestClass() + { + BoolProperty = true, + StringProperty = "LoremIpsum", + DoubleProperty = Math.PI, + ArrayProperty = new int[] { 4, 8, 15, 16, 23, 42 }, + ObjectProperty = new TestClass() { StringProperty = "DolorSitAmet" } + }; + + private string GetSampleJson() + => Regex.Replace( + @"{ + ""BoolProperty"":true, + ""StringProperty"":""LoremIpsum"", + ""DoubleProperty"":3.1415926535897931, + ""ArrayProperty"":[4,8,15,16,23,42], + ""ObjectProperty"": + { + ""BoolProperty"":false, + ""StringProperty"":""DolorSitAmet"", + ""DoubleProperty"":0, + ""ArrayProperty"":null, + ""ObjectProperty"":null + } + }", @"\s+", ""); + + private string GetSampleImproperlyFormattedJson() + => Regex.Replace( + @"{ + ""boolProperty"":true, + ""stringProperty"":""LoremIpsum"", + ""doubleProperty"":3.1415926535897931, + ""arrayProperty"":[4,8,15,16,23,42], + ""objectProperty"": + { + ""boolProperty"":false, + ""stringProperty"":""DolorSitAmet"", + ""doubleProperty"":0, + ""arrayProperty"":null, + ""objectProperty"":null + }, + }", @"\s+", ""); + + private class TestClass + { + public bool BoolProperty { get; set; } + + public string StringProperty { get; set; } + + public double DoubleProperty { get; set; } + + public int[] ArrayProperty { get; set; } + + public TestClass ObjectProperty { get; set; } + } + } +} From 925531a40b1df34ebbd8d05699fe5b2d9fdc8b61 Mon Sep 17 00:00:00 2001 From: kubinko <47024569+kubinko@users.noreply.github.com> Date: Tue, 26 Nov 2019 09:57:24 +0100 Subject: [PATCH 2/2] Update README.md --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 44f840c..70d5551 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ To contribute with new topics/information or make changes, see [contributing](ht * [ASP.NET Core Extensions](#aspnet-core-extensions) * [Database Migrations](#database-migrations) * [Id Generators](#id-generators) +* [Converters](#converters) ### ASP.NET Core Extensions @@ -155,3 +156,18 @@ public void ConfigureServices(IServiceCollection services) .InitDatabaseForIdGenerator(); } ``` + +### Converters + +KORM supports custom converters (via [IConverter](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM/Kros.KORM.Converter.IConverter.html) implementation) for converting values from DB to objects and vice versa. These converters are set for individual columns in `OnModelCreating` method of database configuration class (`DatabaseConfigurationBase`). + +If you need to convert text formatted as JSON from database to entity, you can use pre-defined converter - `JsonConverter`: + +``` csharp +public override void OnModelCreating(ModelConfigurationBuilder modelBuilder) +{ + modelBuilder.Entity() + .HasTableName(MyEntityTableName) + .Property(x => x.MySerializableProperty).UseConverter(); +} +```