繁体   English   中英

如何使用泛型类型配置AutoMapper

[英]How to configure AutoMapper with generic types

我试图在我的实体中实现属性版本跟踪。 使用TrackedProperty的模式作为我的可跟踪属性;

public class PropertyVersion<TValue, TVersion>
{
    public TVersion Version { get; set; }
    public TValue Value { get; set; }
}


public class TrackedProperty<TValue, TVersion> : List<PropertyVersion<TValue, TVersion>>
{

}

例如,在我的存储库中,我将保留TrackedFoo对象,并且我将能够在Foo检索特定版本(在这种情况下版本被描述为Time对象)的数据。

public class TrackedFoo
{
    public string Id { get; set; }
    public TrackedProperty<string, DateTime> Name { get; set; }
}

public class Foo
{
    public string Id { get; set; }
    public string Name { get; set; }
}

我想尽可能保持通用。 所以我尝试使用AutoMapper但是我无法以通用的方式配置它,我不需要配置每个TrackedTypeXTypeX映射。

我需要在TrackedProperty中获取最后一个PropertyVersion项,并将其Value属性映射到TValue类型

能帮我找到解决这个问题的方法吗?

我可以减少变量类型的数量(就是你所谓的<>?之间的东西,无论如何)到单一使用

DateTrackedProperty<TValue> : TrackedProperty<TValue,DateTime>
IntegerTrackedProperty<TValue> : TrackedProperty<TValue, int>
StringTrackedProperty<TValue> : TrackedProperty<TValue, string>

我很乐意为这三种类型编写AutoMapper配置。

最后,我设法通过将以下内容放在MappingProfile中来创建通用映射配置文件(只有一种方式)

CreateMap(typeof(PropertyVersion<,>), typeof(object)).ConvertUsing(typeof(PropertyVersionToValueConverter<,>));
CreateMap(typeof(TrackedProperty<,>), typeof(PropertyVersion<,>)).ConvertUsing(typeof(TrackedPropertyToPropertyVersionConverter<,>));
CreateMap(typeof(TrackedProperty<,>), typeof(object)).ConvertUsing(typeof(TrackedPropertyToValueConverter<,>));

哪里

public class PropertyVersionToValueConverter<TValue, TVersion> : ITypeConverter<PropertyVersion<TValue, TVersion>, TValue>
{
    public TValue Convert(PropertyVersion<TValue, TVersion> source, TValue destination, ResolutionContext context)
    {
        if (source != null)
            return source.Value;
        return default(TValue);
    }
}

public class TrackedPropertyToPropertyVersionConverter<TValue, TVersion> : ITypeConverter<TrackedProperty<TValue, TVersion>, PropertyVersion<TValue, TVersion>>
{
    public PropertyVersion<TValue, TVersion> Convert(TrackedProperty<TValue, TVersion> source, PropertyVersion<TValue, TVersion> destination, ResolutionContext context)
    {
        if (source != null && source.Count > 0)
            return source.Last();

        else return default(PropertyVersion<TValue, TVersion>);
    }
}

public class TrackedPropertyToValueConverter<TValue, TVersion> : ITypeConverter<TrackedProperty<TValue, TVersion>, TValue>
{
    public TValue Convert(TrackedProperty<TValue, TVersion> source, TValue destination, ResolutionContext context)
    {
        var vers = context.Mapper.Map(source, typeof(TrackedProperty<TValue, TVersion>), typeof(PropertyVersion<TValue,TVersion>));
        return (TValue)context.Mapper.Map(vers, typeof(PropertyVersion<TValue, TVersion>), typeof(TValue));
    }
}

第一个映射行提取PropertyVersion.Value。

第二个映射行假设我只需要TrackedProperty中的最后一个版本并提取该版本。

第三行将所有内容组合在一起。

我可以将所有内容组合成一个并拥有一个CreateMap行和一个转换器,但这很简单。

自动播放器的整个想法是在彼此之间映射特定对象。 当我们使用泛型时,我们创建了一个辅助函数:

public static class AutoMaps
{
    public static void Initialize()
    {
        Mapper.Initialize(cfg =>
        {
            CreateGenericMapping<CatModel>(cfg);
        });
    }
    public static void CreateCatMapping<TCatType>(IMapperConfigurationExpression cfg)
    {
        cfg.CreateMap<TCatType, Cat>();
        cfg.CreateMap<Cat, TCatType>();
    }
}

当您尝试将Foo映射到TrackedFoo ,因为它们具有相同的属性名称,所以一开始一切都会好的。 当AutoMapper尝试将您的Foo的属性Namestring )转换为TrackedProperty<string,DateTime>属性NameTrackedProperty<string,DateTime> )时TrackedFoo

由于AutoMapper不知道如何在stringTrackedProperty<,>之间进行natevely转换,因此它将失败。

但是,您可以教AutoMapper如何在这些类型之间进行转换。 为此,您需要一个自定义类型转换器

public class TrackedPropertyConverter<TValue, TVersion> : ITypeConverter<TrackedProperty<TValue, TVersion>, TValue>
{
    public TValue Convert(TrackedProperty<TValue, TVersion> source, TValue destination, ResolutionContext context)
    {
        return source.First().Value;
    }
}

然后你这样配置:

  Mapper.Initialize(
            cfg =>
            {
                cfg.CreateMap<TrackedFoo, Foo>();

                cfg.CreateMap<TrackedProperty<string, DateTime>, string>().ConvertUsing<TrackedPropertyConverter<string,DateTime>>();
                cfg.CreateMap<TrackedProperty<int, DateTime>, int>().ConvertUsing<TrackedPropertyConverter<int, DateTime>>();
                cfg.CreateMap<TrackedProperty<double, DateTime>, double>().ConvertUsing<TrackedPropertyConverter<double, DateTime>>();
            }
        );

Mapper.AssertConfigurationIsValid();

以下是一个示例用法:

var tracked = new TrackedFoo
{
    Id = "SomeGuid",
    Name = new TrackedProperty<string, DateTime> {
        new PropertyVersion<string, DateTime> { Value = "FooBar", Version = new DateTime(2017, 2, 28) }
    },
    Value = new TrackedProperty<int, DateTime> {
        new PropertyVersion<int, DateTime> { Value = 456, Version = new DateTime(2017, 2, 28) }
    }
};

var foo = Mapper.Map<Foo>(tracked);

Console.WriteLine("Id: {0} | Name: {1} | Value: {2}", foo.Id, foo.Name, foo.Value);
Console.ReadLine();

这是教授AutoMapper如何在类型之间进行转换的通用方法,无论这些类型的哪些对象正在转换(例如Foo到TrackedFoo / Bar到TrackedBar / Person到TrackedPerson)。

您必须显式配置每个类型 (string,int,double),就像它们页面中的示例一样,但是您只需执行一次,您不必使用跟踪属性对所有可能的类执行此操作。

此外,您的存储库负责将版本值作为参数(如DateTime ),并使用您为该版本请求的单个值获取TrackedProperty ,因为您不能为同一版本提供多个值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM