2010-01-29 2 views
4

Я только недавно начал использовать Entity Framework 1.0 и считаю, что я начинаю ощущать боли, о которых все говорят. Я пытаюсь использовать лучшие практики, поэтому у меня есть набор DTO, который сопоставляется с моими объектами с помощью AutoMapper.Entity Framework, AutoMapper, обновления для обработки объектов

Настоящий улов - это когда я пытаюсь обновить объект. Первым было то, что я не мог найти способ создания нового объекта, переноса данных из моего 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, а затем вызвать 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, так как он используется в свойстве EntityKey на видео сущности. Прекрасный. Я настроил сопоставления, так что, когда я сопоставил свой DTO с EF Entity, свойство EntityKey получит значение. Теперь мне нужен способ сделать исключение для этого правила сопоставления, но не знаю, с чего начать. Я полагаю, что я мог бы создать совершенно новое правило сопоставления прямо в этом методе и установить свойства EntityKey & VideoId, которые будут игнорироваться, но это кажется довольно неряшливым. Кроме того, я не уверен, что создание, созданное на этом этапе, будет придерживаться. Если он переопределит начальную настройку, которая позволила DTO сопоставить значение EntityKey на объекте, это могло бы иметь обратные последствия совершенно другим способом.

У кого-нибудь есть идея?

ответ

6

AutoMapper

Ваша первая проблема заключается в том, что, насколько я знаю, AutoMapper не предназначен для перехода от DTO-> Entity только Entity-> DTO. Это может измениться недавно, поэтому я не уверен. Смотрите эту ссылку для получения дополнительной информации о том, что automapper разработан, чтобы сделать: The case for two way mapping

PK Mapping

Вы говорите: «правило Mapping прямо в этом методе и установите EntityKey & VideoID свойства должны быть проигнорированы, но кажется довольно неряшливым "

Я не думаю, что это неряшливо. Вы действительно не должны прикасаться к EntityKey/PK после его сохранения и, вероятно, должны каким-то образом кодифицировать свою статичность.

Entity Framework

«Теперь мы перейдем к прекрасной EF вопросу не разрешено изменять свойства, VideoID, так как он используется в свойстве EntityKey на видео сущности. Прекрасный.»

Lovely? EF не заставляет вас не обновлять ПК. Внутри сгенерированных моделей есть проверка изменения свойств внутри сеттера для ваших ключей. Решением было бы изменение сгенерированного кода. В зависимости от вашей волатильности модели это может оказаться нецелесообразным, но это вариант.

+0

jfar: Спасибо за ваш ответ. Прежде всего, что вы имеете в виду AFAIK AutoMapper? Я имею в виду AutoMapper здесь: http://code.google.com/p/automapperhome/. Что касается PK Mapping, я говорю об определении всех сопоставлений в одном месте и не засоряя мой код операторами .CreateMap во всем коде. Проблема здесь в том, что мне нужно косвенно сопоставить мой DTO с моим Entity по-разному в зависимости от того, создаю ли я новую запись в своем db или обновляю запись в своем db. Больше на AutoMapper за секунду ... закончилось символов ... – jason

+1

Хорошо, вы упомянули, что Automapper не предназначался для перехода из DTO -> EF Entity, но должен был быть только EF -> DTO. Если это так, как я должен обновлять свою базу данных через объекты EF, когда объекты, используемые в моем представлении и контроллере, являются объектами DTO? Я не пытаюсь быть снисходительным или чем-то еще. Я просто пытаюсь найти правильный способ обработки вставок и обновлений, не привязывая мое приложение к конкретной реализации доступа к данным. Я открыт для любых предложений, которые у вас могут быть. – jason

+0

AFAIK = насколько я знаю, извините за неясность – jfar

0

У меня такой же сценарий. Единственное решение, которое я получил, это игнорировать поле PK в сопоставлении с DTO -> Entity.

Такое правило может быть достигнуто с помощью следующей строки кода во время конфигурации Automapper:

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

Насколько я знаю, единственный способ получить EF работает с обособленными сущностями отображающих DTO к Сущности вы получили от БД до SaveChanges (как и в примере).

1

Это может помочь, если вы хотите, чтобы избежать сдачи .Ignore() с на каждый объект, который требуется Карта.

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

В сущности, вы бы настроить AutoMapper игнорировать все свойства сущностей, которые не являются скаляром:

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

Возможно, некоторые дополнительные работы могут быть добавлены, чтобы избежать сброса, если свойство является PK (свойство в примере EdmScalarPropertyAttribute (EntityKey == true?) сообщает об этом).

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()) заявлении. Без этого функция return false и отображение не будут работать.