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

时间:2010-01-27 14:25:24

标签: c# asp.net-mvc entity-framework orm automapper

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

        Mapper.CreateMap<VideoDTO, Video>()
            .ForMember(dest => dest.EntityKey, opt =>   
opt.ResolveUsing<VideoEntityKeyResolver>());

VideoEntityKeyResolver类如下所示:

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

我想知道是否有一种更通用的方法来实现这一点,我可以拥有一个带有构造函数的类,该构造函数在构造函数中包含实体集名称,键属性名称和键值。

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

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

1 个答案:

答案 0 :(得分: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));
    }
}

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);
}

然后你会改变你的代码如下(假设VideoId是一个Guid):

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

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

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

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