Используйте automapper для обновления Entity Framework Entity - PullRequest
9 голосов
/ 18 октября 2011

Я пытаюсь использовать Entity Framework и заставить 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 для возврата одной сущности.)

Проблема, с которой я столкнулся, связана с отношениями.Я получаю эту ошибку при обновлении (вставки работают нормально):

Операция не выполнена: отношение не может быть изменено, так как одно или несколько свойств внешнего ключа не могут быть обнулены.Когда в отношение вносится изменение, для соответствующего свойства внешнего ключа устанавливается нулевое значение.Если внешний ключ не поддерживает нулевые значения, необходимо определить новое отношение, свойству внешнего ключа должно быть присвоено другое ненулевое значение или несвязанный объект должен быть удален.

IЯ предполагаю, что automapper не обновляет так, как я хочу.Исходя из сообщения об ошибке и поиска в Google, я предположил, что мои отношения, которые являются коллекциями (и, возможно, даже не являются коллекциями), восстанавливаются Automapper.

Как я могу сказать Automapper просто обновитьи не переделывать какие-либо объекты или коллекции?

Догадки:

Я читал, что, возможно, мне нужно использовать опцию UseDestinationValue для autopper.Я вернулся и вставил это во все свои коллекции. Но когда я это сделаю, мои вставки завершатся неудачно с нарушением внешнего ключа.

Отображения кода:

Использование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();

Что мне нужно, чтобы я мог вставить и обновить?

1 Ответ

0 голосов
/ 16 ноября 2011

Я думаю, что вы хотите, чтобы AutoMapper не создавал вашу сущность EF и не брал ту, которую вы ей отправили.В версии 2.0 автоматического картографирования есть метод перегрузки на карту, где вы можете в основном передать свой делегат datacontext и позволить EF создать ваш объект.

Пожалуйста, посмотрите эту статью .

...