4

我最近才开始使用 Entity Framework 1.0,相信我开始感受到每个人都在谈论的痛苦。我正在尝试使用最佳实践,因此我有一组通过 AutoMapper 映射到我的实体和从我的实体映射的 DTO。

真正的问题是当我试图更新一个对象时。第一个问题是我找不到创建新实体的方法,从我的 DTO 传输数据,并且仍然让实体 ObjectContext 意识到它已被更改。我使用了以下代码:

public VideoDTO UpdateVideo(VideoDTO pVideo)
        {
            Video video = new Video();
            Mapper.Map(pVideo, video);
            context.Attach(video); //Successfully attaches
            context.ApplyPropertyChanges("Videos", video);  // no changes made as far as entity knows b/c it was attached in it's updated state
            context.SaveChanges(); //doesn't save the entity                
            return pVideo;
        }

然后我想,也许我需要先从数据库中获取实体,附加到上下文,调用 Mapper 上的 Map 方法,然后调用 SaveChanges。这是我所做的:

    public VideoDTO UpdateVideo(VideoDTO pVideo)
    {
        Video video = context.Videos.Where(v => v.VideoId == pVideo.VideoId).FirstOrDefault();
        Mapper.Map(pVideo, video); //Error here: Can't change VideoId value on Video entity
        //context.Attach(video);
        //context.ApplyPropertyChanges("Videos", video);
        context.SaveChanges();

        return pVideo;
    }

现在我们遇到了一个可爱的 EF 问题,即不允许更改属性 VideoId,因为它由 Video 实体上的 EntityKey 属性使用。迷人的。我已经设置了映射,以便当我从 DTO 映射到 EF 实体时,EntityKey 属性将获得一个值。现在我需要一种方法来对该映射规则进行例外处理,但不知道从哪里开始。我想我可以在这个方法中创建一个全新的映射规则并将 EntityKey 和 VideoId 属性设置为被忽略,但这似乎很草率。此外,我不确定此时创建的映射是否会保留。如果它覆盖了允许 DTO 将值映射到实体上的 EntityKey 的初始设置,那将以完全不同的方式适得其反。

有人有更好的主意吗?

4

5 回答 5

6

自动映射器

您的第一个问题是,据我所知,AutoMapper 并非旨在从 DTO-> Entity only Entity-> DTO 开始。这可能最近发生了变化,所以我不太确定。有关 automapper 设计用途的更多信息,请参阅此链接: 双向映射的案例

PK映射

您说:“在此方法中正确映射规则并将 EntityKey 和 VideoId 属性设置为被忽略,但这似乎很草率”

我不认为那是草率的。你真的不应该在实体键/PK 被持久化后触摸它,并且可能应该以某种方式编码它的静态性。

实体框架

“现在我们遇到了一个可爱的 EF 问题,即不允许更改属性 VideoId,因为它被 Video 实体上的 EntityKey 属性使用。可爱。”

迷人的?EF 不会强迫你不要更新你的 PK。在生成的模型内部,您的密钥的设置器中有一个属性更改检查。解决方案是更改生成的代码。根据您的模型波动性,这可能不实用,但它是一种选择。

于 2010-01-31T02:16:03.887 回答
3

尝试映射到现有对象:

entity = Mapper.Map<MyDTO, NyEntity>(dto, entity); 

并保持 Ignore() 就位。

http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1

于 2011-12-29T15:38:58.677 回答
1

如果您想避免将.Ignore()s 放在要映射的每个实体上,这可能会有所帮助。

http://www.prosoftnearshore.com/blog/post/2012/03/14/Using-AutoMapper-to-update-Entity-Framework-properties.aspx

本质上,您可以将 AutoMapper 配置为忽略所有非标量的 Entity 属性:

AutoMapper.Mapper.CreateMap<EntityType, EntityType>()
    .ForAllMembers(o => {
         o.Condition(ctx =>
             {
                 var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping

                if (!members.Any())
                    return false;
                return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set
            });
    });

EdmScalarPropertyAttribute如果属性是 PK(实例 ( EntityKey == true?) 中的属性告诉您这一点),也许可以添加一些额外的工作以避免重置。

于 2012-03-14T22:21:33.563 回答
1

我在同样的情况下。我得到的唯一解决方案是忽略 DTO -> Entity 映射中的 PK 字段。

这样的规则可以在 Automapper 配置期间通过以下代码行来实现:

 Mapper.CreateMap<MyDTO, MyEntity>().ForMember("EntityPK",r=>r.Ignore());

据我所知,让 EF 与 Detached Entities 一起工作的唯一方法是将 DTO 映射到在 SaveChanges 之前从 DB 获得的实体(正如您在示例中所做的那样)。

于 2010-06-05T17:33:03.540 回答
0

请注意,“Mauricio Morales”提供的示例仅在您不使用前缀时才有效。如果您使用它们,那么您需要以或多或少的方式稍微更改上面的代码,如下所示:

    Mapper.CreateMap<tempOR_Order, OR_Order>()
        .ForMember(m => m.OR_ID, exp => exp.Ignore())
        .ForMember(m => m.OR_CU_ID, exp => exp.Ignore())
        .ForAllMembers(o => o.Condition(ctx =>
        {
            var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping

            if (!members.Any())
            {
                members = ctx.Parent.SourceType.GetMember("temp" + ctx.MemberName);
                if (!members.Any())
                    return false;
            }

            return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set
        }));

也就是说,您需要在if (!members.Any())语句中包含额外的检查。没有这个,函数返回 false 并且映射将不起作用。

于 2012-08-09T12:41:09.080 回答