【问题标题】:Is there a generic way of using AutoMapper's ValueResolver to map EntityKey values for EF Entities?是否有使用 AutoMapper 的 ValueResolver 映射 EF 实体的 EntityKey 值的通用方法?
【发布时间】:2011-01-09 23:48:53
【问题描述】:

不确定标题是否有意义,但这就是我正在做的事情。我正在使用 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 存储库对象)的构造函数中执行此操作,但我认为这相当昂贵且不正确,但它确实有效。

【问题讨论】:

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


    【解决方案1】:

    我还没有去测试这个,但以下应该可以工作:

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

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

    【讨论】:

    • 感谢您的详细回复。大部分都在我的头上,但我比你更重要。我仍在努力使用 lambda 等。无论如何,您是否知道是否有一种自动映射器方法允许您将计算值显式分配给属性?如果是这种情况,我可以创建一个带有必要参数的 EntityKey 对象,并将该值映射到我的实体上的 EntityKey 属性。我一直在研究 MapFrom AutoMapper 方法,但还没有时间深入研究。
    • 我本来打算建议作为一种更简单的方法,但决定直接回答您的问题。我会将其添加到答案中。 (另外,如果您发现它满足您的需求,请不要忘记投票和/或接受答案)
    • 感谢您在这个问题上的超越。这真的帮助了我!我确实继续并决定只映射到 EntityKey 属性,这似乎奏效了。
    猜你喜欢
    • 1970-01-01
    • 2013-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    相关资源
    最近更新 更多