6

不确定标题是否有意义,但这就是我正在做的事情。我正在使用 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;
    }
}

我想知道是否有一种更通用的方法来执行此操作,我可以有一个带有构造函数的类,该构造函数在构造函数中获取实体集名称、键属性名称和键值。

我考虑过只为我的 DTO 对象添加一个 EntityKey 属性,这听起来很像跨越流,因为创建 DTO 对象的全部目的是在我的应用程序的其余部分中严格与我的数据层的联系。

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

4

1 回答 1

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

TheExpressionHelper是一个静态类,我用它来帮助评估各种情况下的表达式。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)));

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

于 2010-01-28T03:55:10.323 回答