我正在尝试在我的实体中实现属性版本跟踪。使用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
对象,并且我将能够在{{1}中检索特定版本的数据(在这种情况下,版本被描述为Time对象)来自。
Foo
我希望尽可能保持通用性。所以我尝试使用AutoMapper,但我无法以通用的方式配置它,我不需要配置每个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; }
}
到TrackedTypeX
的映射。
我需要获取TrackedProperty中的最后一个PropertyVersion项并将其Value属性映射到TValue类型
你能帮我找到解决这个问题的方法吗?
我可以使用
减少变量类型的数量(就是你所谓的&lt;&gt;?之间的东西)TypeX
我可以为这三种类型编写AutoMapper配置。
答案 0 :(得分:3)
最后我设法创建了一个通用的映射配置文件(只有一种方式) 将以下内容放在我的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行和一个转换器,但这很简单。
答案 1 :(得分:0)
自动播放器的整个想法是在彼此之间映射特定对象。 当我们使用泛型时,我们创建了一个辅助函数:
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>();
}
}
答案 2 :(得分:0)
当您尝试将Foo
映射到TrackedFoo
时,因为它们具有相同的属性名称,所以一开始一切都会好的。当AutoMapper尝试将您的string
的属性名称(Foo
)转换为属性名称(TrackedProperty<string,DateTime>
)时,会出现问题你的TrackedFoo
。
由于AutoMapper不知道如何在string
和TrackedProperty<,>
之间进行natevely转换,因此会失败。
但是,您可以教AutoMapper如何在这些类型之间进行转换。为此,您需要Custom Type Converter:
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 to TrackedPerson)。
你必须显式配置每种类型(string,int,double),就像它们页面中的示例一样,但是你只需要执行一次,你不必为所有可能的类做到这一点使用跟踪属性。
此外,您的存储库负责将版本值作为参数(例如DateTime
),并使用您为该版本请求的单个值获取TrackedProperty
,因为您不能拥有同一版本的多个值。