我有一个我要映射到实体的DTO。该实体具有一些使用MaxLength
属性修饰的属性。
我希望AutoMapper在根据每个属性的MaxLength
映射到我的实体时截断来自DTO的所有字符串,以便在保存实体时不会出现验证错误。
因此,如果实体的定义如下:
public class Entity
{
[MaxLength(10)]
string Name { get; set; }
}
我希望这样做:
var myDto = new MyDto() { Name = "1231321312312312312312" };
var entity = Mapper.Map<Entity>(myDto);
结果entity
应将Name
限制为最多10个字符。
答案 0 :(得分:2)
我不确定这是一个放置逻辑的好地方,但这是一个应该适用于您的情况的示例(AutoMapper 4.x):Custom Mapping with AutoMapper
在此示例中,我在我的实体上阅读自定义MapTo
属性,您可以对MaxLength
执行相同操作。
这是使用当前版本的AutoMapper(6.x)
的完整示例class Program
{
static void Main(string[] args)
{
Mapper.Initialize(configuration =>
configuration.CreateMap<Dto, Entity>()
.ForMember(x => x.Name, e => e.ResolveUsing((dto, entity, value, context) =>
{
var result = entity.GetType().GetProperty(nameof(Entity.Name)).GetCustomAttribute<MaxLengthAttribute>();
return dto.MyName.Substring(0, result.Length);
})));
var myDto = new Dto { MyName = "asadasdfasfdaasfasdfaasfasfd12" };
var myEntity = Mapper.Map<Dto, Entity>(myDto);
}
}
public class Entity
{
[MaxLength(10)]
public string Name { get; set; }
}
public class Dto
{
public string MyName { get; set; }
}
答案 1 :(得分:0)
我得到了一些代码:
class Program
{
static void Main(string[] args)
{
Mapper.Initialize(configuration =>
configuration.CreateMap<Dto, Entity>()
.ForMember(x => x.Name, e => e.MapFrom(d => d.MyName))
.ForMember(x => x.Free, e => e.MapFrom(d => d.Free))
.ForMember(x => x.AnotherName, e => e.MapFrom(d => d.Another))
.LimitStrings());
var dto = new Dto() { MyName = "asadasdfasfdaasfasdfaasfasfd12", Free = "ASFÑLASJDFÑALSKDJFÑALSKDJFAMLSDFASDFASFDASFD", Another = "blalbalblalblablalblablalblablalblablabb"};
var entity = Mapper.Map<Entity>(dto);
}
}
public static class Extensions
{
public static IMappingExpression<TSource, TDestination> LimitStrings<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var sourceType = typeof(TSource);
var destinationType = typeof(TDestination);
var existingMaps = Mapper.GetAllTypeMaps().First(b => b.SourceType == sourceType && b.DestinationType == destinationType);
var propertyMaps = existingMaps.GetPropertyMaps().Where(map => !map.IsIgnored() && ((PropertyInfo)map.SourceMember).PropertyType == typeof(string));
foreach (var propertyMap in propertyMaps)
{
var attr = propertyMap.DestinationProperty.MemberInfo.GetCustomAttribute<MaxLengthAttribute>();
if (attr != null)
{
expression.ForMember(propertyMap.DestinationProperty.Name,
opt => opt.ResolveUsing(new StringLimiter(attr.Length, (PropertyInfo) propertyMap.SourceMember)));
}
}
return expression;
}
}
public class StringLimiter : IValueResolver
{
private readonly int length;
private readonly PropertyInfo propertyMapSourceMember;
public StringLimiter(int length, PropertyInfo propertyMapSourceMember)
{
this.length = length;
this.propertyMapSourceMember = propertyMapSourceMember ?? throw new ArgumentNullException(nameof(propertyMapSourceMember));
}
public ResolutionResult Resolve(ResolutionResult source)
{
var sourceValue = (string)propertyMapSourceMember.GetValue(source.Context.SourceValue);
var result = new string(sourceValue.Take(length).ToArray());
return source.New(result);
}
}
请告诉我它是否有意义或有一些错误!
感谢@bidou提示。这是我获取灵感的帖子here
答案 2 :(得分:0)
对于AutoMapper 8.0,并基于@SuperJMN的答案:
在您的项目中创建文件AutoMapperExtensions.cs:
using AutoMapper;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
namespace YourNamespaceHere
{
public static class AutoMapperExtensions
{
public static IMappingExpression<TSource, TDestination> LimitStrings<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var sourceType = typeof(TSource);
var destinationType = typeof(TDestination);
var existingMaps = Mapper.Configuration.GetAllTypeMaps().First(b => b.SourceType == sourceType && b.DestinationType == destinationType);
var propertyMaps = existingMaps.PropertyMaps.Where(map => !map.Ignored && ((PropertyInfo)map.SourceMember).PropertyType == typeof(string));
foreach (var propertyMap in propertyMaps)
{
var attr = propertyMap.DestinationMember.GetCustomAttribute<MaxLengthAttribute>();
if (attr != null)
{
expression.ForMember(propertyMap.DestinationMember.Name,
opt => opt.ConvertUsing(new StringLimiter(attr.Length), propertyMap.SourceMember.Name));
}
}
return expression;
}
}
public class StringLimiter : IValueConverter<string, string>
{
private readonly int length;
private readonly PropertyInfo propertyMapSourceMember;
public StringLimiter(int length)
{
this.length = length;
propertyMapSourceMember = propertyMapSourceMember ?? throw new ArgumentNullException(nameof(propertyMapSourceMember));
}
public string Convert(string sourceMember, ResolutionContext context)
{
var sourceValue = (string)propertyMapSourceMember.GetValue(sourceMember);
return new string(sourceValue.Take(length).ToArray());
}
}
}
...,然后将以下内容添加到CreateMap的末尾(例如):
.ForMember(
dest => dest.ShortField,
opts => opts.MapFrom(src => src.LongField))
.LimitStrings();