首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >地图IReadOnlyDictionary EfCore

地图IReadOnlyDictionary EfCore
EN

Stack Overflow用户
提问于 2020-08-25 04:26:27
回答 1查看 189关注 0票数 0

我有一个实体,它有一个字典字段,它使用这样的支持字段。

代码语言:javascript
复制
private Dictionary<string, string> _communicationEventProperties = new Dictionary<string, string>();
public IReadOnlyDictionary<string, string> CommunicationEventProperties => new ReadOnlyDictionary<string,string>(_communicationEventProperties);

我已经使用Fluent正确地将它映射到SQL中的JSON。

然而,当我试图调用我的实体时,我会得到以下错误。

代码语言:javascript
复制
System.InvalidCastException: Unable to cast object of type 'System.Collections.ObjectModel.ReadOnlyDictionary`2[System.String,System.String]' to type 'System.Collections.Generic.Dictionary`2[System.String,System.String]'

它似乎没有很好地在类型之间映射。

我不知道为什么没有映射/如何使它正确地映射。

我还将附加整个堆栈跟踪:

代码语言:javascript
复制
[InvalidCastException: Unable to cast object of type 'System.Collections.ObjectModel.ReadOnlyDictionary`2[System.String,System.String]' to type 'System.Collections.Generic.Dictionary`2[System.String,System.String]'.]
   lambda_method(Closure , MaterializationContext ) +1237
   Microsoft.EntityFrameworkCore.Query.EntityLoadInfo.Materialize() +22
   Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.GetEntity(IKey key, EntityLoadInfo entityLoadInfo, Boolean queryStateManager, Boolean throwOnNullKey) +201
   Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.BufferedEntityShaper`1.Shape(QueryContext queryContext, ValueBuffer& valueBuffer) +198
   Microsoft.EntityFrameworkCore.Query.Internal.<BufferlessMoveNext>d__12.MoveNext() +1121
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.<ExecuteAsync>d__7`2.MoveNext() +174
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   Microsoft.EntityFrameworkCore.Query.Internal.<MoveNext>d__11.MoveNext() +637
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   Microsoft.EntityFrameworkCore.Query.Internal.<MoveNext>d__3.MoveNext() +210
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Linq.<FirstOrDefault_>d__165`1.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\First.cs:144
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   Microsoft.EntityFrameworkCore.Query.Internal.<MoveNext>d__3.MoveNext() +243
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Linq.<MoveNextCore>d__7.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Select.cs:106
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Linq.<MoveNext>d__10.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\AsyncIterator.cs:109
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   Microsoft.EntityFrameworkCore.Query.Internal.<MoveNext>d__5.MoveNext() +634
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   Microsoft.EntityFrameworkCore.Query.Internal.<ExecuteSingletonAsyncQuery>d__21`1.MoveNext() +447
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +29
   Metis.Communications.Core.EFCore.Interactions.EmailCommunications.GetEmailCommunicationDetails.<<-ctor>g__EmailCommunicationExists|1>d.MoveNext() in C:\Users\ethalacker\source\repos\Metis\src\Communication\Metis.Communications.Core.EFCore\Interactions\EmailCommunications\GetEmailCommunicationDetails\GetEmailCommunicationDetailsValidator.cs:25
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   FluentValidation.Validators.<ValidateAsync>d__7.MoveNext() in /home/jskinner/code/FluentValidation/src/FluentValidation/Validators/PropertyValidator.cs:65
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) +26
   FluentValidation.Internal.<ValidateAsync>d__66.MoveNext() in /home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:396
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   FluentValidation.<ValidateAsync>d__14.MoveNext() in /home/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:146
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Runtime.CompilerServices.ConfiguredTaskAwaiter.GetResult() +29
   Metis.SharedKernel.Interactions.<IsValid>d__10.MoveNext() in C:\Users\ethalacker\source\repos\Metis\src\Shared\Metis.SharedKernel\Interactions\InteractionHandler.cs:77
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +29
   Metis.SharedKernel.Interactions.<Handle>d__8.MoveNext() in C:\Users\ethalacker\source\repos\Metis\src\Shared\Metis.SharedKernel\Interactions\InteractionHandler.cs:41
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   MediatR.Pipeline.<Handle>d__2.MoveNext() +260
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   MediatR.Pipeline.<Handle>d__2.MoveNext() +733
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +29
   Metis.Web.Pages.SiteConfiguration.Communications.EmailCommunications.EmailCommunicationDetails.<Page>d__3.MoveNext() in C:\Users\ethalacker\source\repos\Metis\src\Metis.Web\Pages\SiteConfiguration\Communications\EmailCommunications\EmailCommunicationDetails\EmailCommunicationDetailsController.cs:38
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64
   System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult) +97
   System.Web.Mvc.Async.<>c__DisplayClass8_0.<BeginInvokeAsynchronousActionMethod>b__1(IAsyncResult asyncResult) +17
   System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +10
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +32
   System.Web.Mvc.Async.<>c__DisplayClass11_0.<InvokeActionMethodFilterAsynchronouslyRecursive>b__0() +58
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +228
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +228
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +228
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +228
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +228
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +228
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +228
   System.Web.Mvc.Async.<>c__DisplayClass7_0.<BeginInvokeActionMethodWithFilters>b__1(IAsyncResult asyncResult) +10
   System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +10
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +34
   System.Web.Mvc.Async.<>c__DisplayClass3_6.<BeginInvokeAction>b__4() +35
   System.Web.Mvc.Async.<>c__DisplayClass3_1.<BeginInvokeAction>b__1(IAsyncResult asyncResult) +100
   System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +10
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +27
   System.Web.Mvc.<>c.<BeginExecuteCore>b__152_1(IAsyncResult asyncResult, ExecuteCoreState innerState) +11
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +29
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +45
   System.Web.Mvc.<>c.<BeginExecute>b__151_2(IAsyncResult asyncResult, Controller controller) +13
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +22
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +26
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10
   System.Web.Mvc.<>c.<BeginProcessRequest>b__20_1(IAsyncResult asyncResult, ProcessRequestState innerState) +28
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +29
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +28
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.<>c__DisplayClass7_0.<InvokeEndHandler>b__0() +30
   System.Web.StepInvoker.Invoke(Action executionStep) +100
   System.Web.<>c__DisplayClass4_0.<Invoke>b__0() +17
   Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule.OnExecuteRequestStep(HttpContextBase context, Action step) +64
   System.Web.<>c__DisplayClass284_0.<OnExecuteRequestStep>b__0(Action nextStepAction) +54
   System.Web.StepInvoker.Invoke(Action executionStep) +84
   System.Web.CallHandlerExecutionStep.InvokeEndHandler(IAsyncResult ar) +113
   System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +126
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-25 19:57:21

我不得不创建一个特殊的json转换器和比较器。在执行IReadOnlyDictionary时,同样可以应用于IReadOnlyList。类将接受属性的类型,然后尝试将其反序列化为字段类型。我有IReadOnlyDictionaryIReadOnlyList的硬编码特例。但是它也可以通过重载(HasJsonConversionWithSerializationType)接受类型。

我还为其他用例添加了一些其他示例。

我的类属性

代码语言:javascript
复制
private Dictionary<string, string> _communicationEventProperties = new Dictionary<string, string>();
public IReadOnlyDictionary<string, string> CommunicationEventProperties => new ReadOnlyDictionary<string,string>(_communicationEventProperties);

private List<TokenValue> _tokenValues = new List<TokenValue>();
public IReadOnlyList<TokenValue> TokenValues => _tokenValues.AsReadOnly();

private List<string> _cCAddresses = new List<string>();
public IReadOnlyList<string> CCAddresses => _cCAddresses.AsReadOnly();

public class TokenValue
{
    public string Key { get; }
    public string Value { get; }

    public TokenValue(string key, string value)
    {
        // using Dawn. Else you can use a normal "?? throw new ArgumentNullException"
        Key = Guard.Argument(key, nameof(Key)).NotNull().NotEmpty().MaxLength(250);
        Value = value;
    }
}

配置文件

代码语言:javascript
复制
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Application.EFCore.Configurations
{
    public class MyEntityConfiguration : IEntityTypeConfiguration<MyEntity>
    {
        public void Configure(EntityTypeBuilder<MyEntity> builder)
        {
            ...

            builder.Property(b => b.CommunicationEventProperties)
                .HasJsonConversion();

            builder.Property(b => b.TokenValues)
                .HasJsonConversion();

            builder.Property(b => b.CCAddresses)
                .HasJsonConversion();
            ...
        }
    }
}

Json转换类

代码语言:javascript
复制
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public static class BuilderExtensions
{
    public static PropertyBuilder<TProperty> HasJsonConversion<TProperty>(this PropertyBuilder<TProperty> propertyBuilder) where TProperty : class
    {
        var serializationType = GetSerializationTypeByConvention<TProperty>();
        return HasJsonConversionWithSerializationType(propertyBuilder, serializationType);
    }

    public static PropertyBuilder<TProperty> HasJsonConversionWithSerializationType<TProperty, TSerialization>(this PropertyBuilder<TProperty> propertyBuilder)
        where TProperty : class
        where TSerialization : TProperty
        => HasJsonConversionWithSerializationType(propertyBuilder, typeof(TSerialization));

    public static PropertyBuilder<TProperty> HasJsonConversionWithSerializationType<TProperty>(this PropertyBuilder<TProperty> propertyBuilder, Type serializationType) where TProperty : class
    {
        Guard.Argument(serializationType, nameof(serializationType)).NotNull().Require(t => typeof(TProperty).IsAssignableFrom(t), t => $"Must be able to assign {nameof(serializationType)} '{t.FullName}' to <{nameof(TProperty)}> '{typeof(TProperty).FullName}'");            

        var converter = MakeConverter<TProperty>(serializationType);
        var comparer = MakeComparer<TProperty>(serializationType);

        propertyBuilder.HasConversion(converter);
        propertyBuilder.Metadata.SetValueConverter(converter);
        propertyBuilder.Metadata.SetValueComparer(comparer);

        return propertyBuilder;
    }

    private static Type GetSerializationTypeByConvention<TProperty>() where TProperty : class
    {
        var typeIsReadOnlyDictionary = typeof(TProperty).IsGenericType && typeof(TProperty).GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>);
        if (typeIsReadOnlyDictionary) return typeof(Dictionary<,>).MakeGenericType(typeof(TProperty).GetGenericArguments());

        var typeIsReadOnlyList = typeof(TProperty).IsGenericType && typeof(TProperty).GetGenericTypeDefinition() == typeof(IReadOnlyList<>);
        if (typeIsReadOnlyList) return typeof(List<>).MakeGenericType(typeof(TProperty).GetGenericArguments());

        return typeof(TProperty);
    }

    private static Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer<TProperty> MakeComparer<TProperty>(Type serializationType)
            => new Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer<TProperty>(
                (l, r) => Serialize(l) == Serialize(r),
                v => v == null ? 0 : Serialize(v).GetHashCode(),
                v => Deserialize<TProperty>(Serialize(v), serializationType));

    private static ValueConverter<TProperty, string> MakeConverter<TProperty>(Type serializationType)
        => new ValueConverter<TProperty, string>(
            v => Serialize(v),
            v => Deserialize<TProperty>(v, serializationType));


    private static TProperty Deserialize<TProperty>(string v, Type serializationType)
    {
        if (v == null) return default;
        return (TProperty)JsonConvert.DeserializeObject(v, serializationType);
    }
    private static string Serialize<TProperty>(TProperty v)
        => JsonConvert.SerializeObject(v
            , Formatting.None
            , new JsonSerializerSettings {
                NullValueHandling = NullValueHandling.Ignore
            });
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63572044

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档