是否有使用AutoMapper的ValueResolver映射EF实体的EntityKey值的通用方法?

jas*_*son 6 c# asp.net-mvc orm entity-framework automapper

不确定标题是否有意义,但这就是我正在做的事情.我正在使用AutoMapper将我的实体框架实体映射到我的DTO对象,反之亦然.当我尝试将DTO数据映射到EF实体时出现问题.EntityKey没有属性映射的属性.为了解决这个问题,我做了以下几点:

        Mapper.CreateMap<VideoDTO, Video>()
            .ForMember(dest => dest.EntityKey, opt =>   
opt.ResolveUsing<VideoEntityKeyResolver>());
Run Code Online (Sandbox Code Playgroud)

VideoEntityKeyResolver类如下所示:

public class VideoEntityKeyResolver : ValueResolver<VideoDTO, EntityKey>
{
    protected override EntityKey ResolveCore(VideoDTO source)
    {
        EntityKey key = new EntityKey("EntityFrameworkTestingEntities.Videos",
            "VideoId", source.VideoId);
        return key;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有更通用的方法这样做我可以有一个带有构造函数的类,它在构造函数中获取实体集名称,键属性名称和键值.

我已经考虑过将一个EntityKey属性添加到我的DTO对象中,这听起来很像穿越流,因为创建DTO对象的重点是在我的应用程序的其余部分严重依赖于我的数据层.

在一个完全不相关的注释(我可以根据需要创建一个新问题),在使用AutoMapper时我需要在哪里定义我的映射?目前我正在我的上下文对象(这是我的EF存储库对象)的构造函数中进行此操作,但我认为这相当昂贵而且不正确,但是,它有效.

mke*_*bbs 8

我还没有测试过这个,但以下应该有效:

public class EntityKeyResolver<T, TProperty> : ValueResolver<T, EntityKey> where T : class
{
    private Expression<Func<T, TProperty>> _propertyExpression;
    private string _qualifiedEntitySetName;
    private string _keyName;

    public EntityKeyResolver(string qualifiedEntitySetName, string keyName, Expression<Func<T, TProperty>> propertyExpression)
    {
        _qualifiedEntitySetName = qualifiedEntitySetName;
        _keyName = keyName;
        _propertyExpression = propertyExpression;
    }

    protected override EntityKey ResolveCore(T source)
    {
        return new EntityKey(_qualifiedEntitySetName, _keyName, ExpressionHelper.GetValue(_propertyExpression));
    }
}
Run Code Online (Sandbox Code Playgroud)

ExpressionHelper是一个静态类,我用它来帮助评估各种情况下的表达式.GetValue方法如下所示:

internal static TProperty GetValue<T, TProperty>(T obj, Expression<Func<T, TProperty>> expression) where T : class
{
    if (obj == null)
    {
        return default(TProperty);
    }

    Func<T, TProperty> func = expression.Compile();

    return func(obj);
}
Run Code Online (Sandbox Code Playgroud)

然后,您将按如下方式更改代码(假设VideoId是Guid):

Mapper.CreateMap<VideoDTO, Video>()         
            .ForMember(dest => dest.EntityKey, opt => opt.ResolveUsing(new EntityKeyResolver<VideoDTO, Guid>("EntityFrameworkTestingEntities.Videos", "VideoId", v => v.VideoId)));
Run Code Online (Sandbox Code Playgroud)

可能比你想要的更冗长.通用解析器的替代方法是使用MapFrom映射实体密钥(它们大致相同的冗长):

Mapper.CreateMap<VideoDTO, Video>()         
                .ForMember(dest => dest.EntityKey, opt => opt.MapFrom(src => new EntityKey("EntityFrameworkTestingEntities.Videos", "VideoId", src.VideoId)));
Run Code Online (Sandbox Code Playgroud)

至于你的另一个问题,我已经养成了创建一个初始化我的map的静态类的习惯,并设置了一个布尔值,表明是否已经创建了映射,因为你只需要为每个AppDomain调用一次.然后,在我的存储库的构造函数中,我只是调用MapInitializer.EnsureMaps();