使用 automapper 更新实体框架实体

发布于 2024-12-11 01:15:34 字数 4470 浏览 0 评论 0原文

我正在尝试使用实体框架并让 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 仅更新而不重新创建任何对象或集合?

猜测:

我读到也许我需要使用 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();

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

I am trying to use Entity Framework and have Automapper update my entity from my contract.

My code looks like this:

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

(Note: I am using the Repository Pattern. dataAccess.FindOne calls CreateQuery to return one entity.)

The problem I am having is with the relationships. I get this error when I do an update (inserts work just fine):

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

I am guessing that automapper is not updating the way I want it to. From the error message and googling around I have surmised that my relationships that are collections (and maybe even the ones that are not collections) are being recreated by Automapper.

How can I tell Automapper to just update and not remake any objects or collections?

Guesses:

I read that maybe I need to use the UseDestinationValue option for automapper. I went back and put that on all my collections But when I do that then my inserts fail with a foreign key violation.

Code Mappings:

Using UseDestinationValue only on one collection (this one inserts but will not update):

//+ 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();

Using UseDestinationValue everywhere (this one does not insert):

//+ 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();

What do I need to so I can insert and update?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

逆蝶 2024-12-18 01:15:34

我认为您想要的是 AutoMapper 不创建您的 EF 实体并获取您发送的实体。在自动映射器的 version2.0 中,有一个重载的映射方法,您基本上可以传递数据上下文委托并让 EF 创建您的对象。

请查看这篇文章

I think what you want is for AutoMapper to not create your EF entity and take the one you sent it. In version2.0 of auto mapper there is an overload to map method where you can basically pass your datacontext delegate and let EF create your object.

Please look at this article.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文