Entity Framework, AutoMapper, обработка обновлений объектов - PullRequest
4 голосов
/ 30 января 2010

Я только недавно начал использовать Entity Framework 1.0 и считаю, что начинаю чувствовать боль, о которой все говорят.Я пытаюсь использовать лучшие практики, поэтому у меня есть набор DTO, которые отображаются на и из моих сущностей через 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;
        }

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

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

Ответы [ 5 ]

6 голосов
/ 31 января 2010

AutoMapper

Ваша первая проблема в том, что, насколько я знаю, AutoMapper не предназначен для перехода от DTO-> Entity only Entity-> DTO. Это могло измениться недавно, поэтому я не совсем уверен. Посмотрите эту ссылку для получения дополнительной информации о том, для чего предназначен autopper: Случай для двустороннего отображения

PK Mapping

Вы говорите: «Правило сопоставления прямо в этом методе и задаете свойства EntityKey & VideoId, которые должны игнорироваться, но это выглядит довольно небрежно»

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

Entity Framework

"Теперь мы подошли к прекрасной проблеме EF: не разрешалось изменять свойство VideoId, поскольку оно используется свойством EntityKey в сущности Video. Lovely."

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

3 голосов
/ 29 декабря 2011

Попробуйте сопоставить существующий объект:

entity = Mapper.Map<MyDTO, NyEntity>(dto, entity); 

И держите Игнорирование () на месте.

http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1

1 голос
/ 15 марта 2012

Это может помочь, если вы не хотите ставить .Ignore() s на каждую сущность, которую хотите сопоставить.

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

По сути, вы должны настроить AutoMapper на игнорирование всех свойств Entity, которые не являются скалярными:

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 голосов
/ 09 августа 2012

Обратите внимание, что пример, предоставленный "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()). Без этого функция вернет false и отображение не будет работать.

0 голосов
/ 05 июня 2010

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

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

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

Насколько я знаю, единственный способ заставить EF работать с Detached Entities - это преобразовать DTO в Entity, который вы получили из DB до SaveChanges (как вы делали в примере).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...