使用 automapper 更新实体框架实体
Posted
技术标签:
【中文标题】使用 automapper 更新实体框架实体【英文标题】:Use automapper to update an Entity Framework Entity 【发布时间】: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();
我需要做什么才能插入和更新?
【问题讨论】:
你能展示你的Order
和OrderContract
课程吗?
@shuniar - 我的合同可以在这里看到:raw.github.com/gist/1296415/…。 Order 类是一个实体对象,非常大。除非有明确的理由,否则我宁愿不让它看起来像样。
您解决了这个问题吗?我也有同样的问题。
AutoMapper 不会合并,它会创建新的。如果要合并,那就不要使用AutoMapper,自己写a -> b 映射方法。
@O.O - AutoMapper 两者都可以。 Mapper.Map(sourceObject, destObject)
【参考方案1】:
我认为您希望 AutoMapper 不创建您的 EF 实体并获取您发送的实体。在 auto mapper 的 version2.0 中有一个重载到 map 方法,您基本上可以传递您的 datacontext 委托并让 EF 创建您的对象。
请看这个article。
【讨论】:
以上是关于使用 automapper 更新实体框架实体的主要内容,如果未能解决你的问题,请参考以下文章