【问题标题】:Use automapper to update an Entity Framework Entity使用 automapper 更新实体框架实体
【发布时间】:2011-12-10 05:58:13
【问题描述】:

我正在尝试使用实体框架并让 Automapper 从我的合同中更新我的实体。

我的代码如下所示:

var temp = OrderContract;
Order order = dataAccess.FindOne<Order>(x => x.OrderId == temp.OrderId) 
              ?? new Order();

Mapper.Map(OrderContract, order);

if (order.OrderId <= 0)
   dataAccess.Add(order);

(注意:我使用的是存储库模式。dataAccess.FindOne 调用 CreateQuery 以返回一个实体。)

我遇到的问题是人际关系。当我进行更新时出现此错误(插入工作正常):

操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

我猜 automapper 没有按照我想要的方式更新。根据错误消息和谷歌搜索,我推测 Automapper 正在重新创建我的集合关系(甚至可能不是集合的关系)。

如何告诉 Automapper 只更新而不重新制作任何对象或集合?

猜测:

我读到也许我需要为 automapper 使用 UseDestinationValue 选项。我回去把它放在我所有的集合上但是当我这样做时,我的插入因外键违规而失败。

代码映射:

仅在一个集合上使用 UseDestinationValue(此集合插入但不会更新):

//+ Source
Mapper.CreateMap<SourceContract, Source>()
    .IgnoreAllNonExisting();

//+ SelectedRequirement
Mapper.CreateMap<SelectedRequirementContract, SelectedRequirement>()
    .ForMember(x => x.SelectedRequirementId, opt => opt.MapFrom(src => src.RequirementId))
    .IgnoreAllNonExisting();

//+ Comment Contract
Mapper.CreateMap<CommentContract, Comment>()
    .ForMember(x => x.CommentText, opt => opt.MapFrom(src => src.Comment))
    .IgnoreAllNonExisting();

//+ Order Automapper setup
Mapper.CreateMap<OrderContract, Order>()
    .ForMember(x => x.Source, opt => opt.MapFrom(src => src.Source))
    .ForMember(x => x.Comment, opt => opt.MapFrom(src => src.Comment))
    //Although a mapping was created for Comment entity,
    //we still need to map the CommentId of the Order entity otherwise it will remain null during an update.
    //Another way to handle this would be to Delete CommentId from the Order entity.
    //However, if anyone updates (Update from model) OrderDataModel.edmx that property would show up again thus causing
    //a null value to be inserted during an update.
    .ForMember(x => x.CommentId, opt => opt.MapFrom(src => src.Comment.CommentId))
    .ForMember(x => x.SelectedRequirements, opt => {opt.UseDestinationValue(); opt.MapFrom(src => src.Requirements);})
    .ForMember(x => x.OrderStateId, opt => opt.MapFrom(src => src.StateId))
    .ForMember(x => x.OrderStateId, opt => opt.MapFrom(src => src.StateId))
    .IgnoreAllNonExisting();

处处使用 UseDestinationValue(这个不插入):

//+ Source
Mapper.CreateMap<SourceContract, Source>()
    .IgnoreAllNonExisting();

//+ SelectedRequirement
Mapper.CreateMap<SelectedRequirementContract, SelectedRequirement>()
    .ForMember(x => x.SelectedRequirementId, opt => { opt.UseDestinationValue(); opt.MapFrom(src => src.RequirementId); })
    .IgnoreAllNonExisting();

//+ Comment Contract
Mapper.CreateMap<CommentContract, Comment>()
    .ForMember(x => x.CommentText, opt => { opt.UseDestinationValue(); opt.MapFrom(src => src.Comment); })
    .IgnoreAllNonExisting();

//+ Order Automapper setup
Mapper.CreateMap<OrderContract, Order>()
    .ForMember(x => x.Source, opt => { opt.UseDestinationValue(); opt.MapFrom(src => src.Source); })
    .ForMember(x => x.Comment, opt => { opt.UseDestinationValue(); opt.MapFrom(src => src.Comment); })
    //Although a mapping was created for Comment entity,
    //we still need to map the CommentId of the Order entity otherwise it will remain null during an update.
    //Another way to handle this would be to Delete CommentId from the Order entity.
    //However, if anyone updates (Update from model) OrderDataModel.edmx that property would show up again thus causing
    //a null value to be inserted during an update.
    .ForMember(x => x.CommentId, opt => { opt.UseDestinationValue(); opt.MapFrom(src => src.Comment.CommentId); })
    .ForMember(x => x.SelectedRequirements, opt => { opt.UseDestinationValue(); opt.MapFrom(src => src.Requirements); })
    .ForMember(x => x.OrderStateId, opt => { opt.UseDestinationValue(); opt.MapFrom(src => src.StateId); })
    .ForMember(x => x.OrderStateId, opt => { opt.UseDestinationValue(); opt.MapFrom(src => src.StateId); })
    .IgnoreAllNonExisting();

我需要做什么才能插入和更新?

【问题讨论】:

  • 你能展示你的OrderOrderContract课程吗?
  • @shuniar - 我的合同可以在这里看到:raw.github.com/gist/1296415/…。 Order 类是一个实体对象,非常大。除非有明确的理由,否则我宁愿不让它看起来像样。
  • 您解决了这个问题吗?我也有同样的问题。
  • AutoMapper 不会合并,它会创建新的。如果要合并,那就不要使用AutoMapper,自己写a -> b 映射方法。
  • @O.O - AutoMapper 两者都可以。 Mapper.Map(sourceObject, destObject)

标签: c# entity-framework entity-framework-4 automapper


【解决方案1】:

我认为您希望 AutoMapper 不创建您的 EF 实体并获取您发送的实体。在 auto mapper 的 version2.0 中有一个重载到 map 方法,您基本上可以传递您的 datacontext 委托并让 EF 创建您的对象。

请看这个article

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多