2010-01-29 10 views
4

최근 엔티티 프레임 워크 1.0을 사용하기 시작한 이래로 나는 모두가 말하는 고통을 느끼기 시작했다고 생각합니다. 모범 사례를 사용하여 AutoMapper를 통해 내 엔터티에 매핑되는 DTO 집합을 사용하려고합니다.엔티티 프레임 워크, AutoMapper, 엔티티 업데이트 처리

실제 잡는 것은 객체를 업데이트하려고 할 때입니다. 첫 번째 문제는 새 엔티티를 만들고 DTO에서 데이터를 전송할 수있는 방법을 찾지 못했지만 엔티티 ObjectContext에서 엔티티가 변경되었음을 알게되었습니다. 아마 난 그냥 SaveChanges를 호출 한 후, 컨텍스트에 연결, 먼저 데이터베이스에서 엔티티를 잡아 매퍼에지도 메소드를 호출 할 필요가

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

그때 생각 : 나는 다음과 같은 코드를 사용했다. 내가 그랬어 여기에 무엇을 :이 비디오 개체의 EntityKey 속성에서 사용 있기 때문에

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

이제 우리는, 재산, 동영상 ID를 변경할 수 없다는 아름다운 EF 문제에 도착. 아름다운. DTO에서 EF Entity로 매핑 할 때 EntityKey 속성이 값을 갖도록 매핑을 설정했습니다. 이제 그 매핑 규칙에 대한 예외를 만들 수있는 방법이 필요하지만 어디에서 시작해야하는지 알지 못합니다. 이 메서드에서 바로 새로운 매핑 규칙을 만들고 EntityKey & VideoId 속성을 무시하도록 설정했는데 꽤 엉뚱한 것 같습니다. 게다가, 나는이 시점에서 생성 된 매핑이 계속 될지 확신하지 못한다. DTO가 엔터티의 EntityKey에 값을 매핑 할 수있는 초기 설정을 오버로드하면 완전히 다른 방식으로 역효과를냅니다.

누구나 더 좋은 아이디어가 있습니까?

답변

6

AutoMapper

첫 번째 문제는 내가 아는 한 AutoMapper이 DTO-> 엔티티에만로 entity> DTO에서 이동하도록 설계되지 않는 것입니다. 이것은 최근에 바뀔 수있어서 정말 잘 모르겠습니다.

당신은 말할 The case for two way mapping

PK 매핑 : automapper을 할 수 있도록 설계되었습니다에 대한 자세한 내용은이 링크를 참조하십시오 "바로이 방법의 매핑 규칙을 무시하는 EntityKey & 동영상 ID 속성을 설정할 수 있지만, 꽤 이상하게 보입니다. "

나는 전혀 엉망이라고 생각하지 않는다. 영속화 된 후에는 EntityKey/PK를 건드려서는 안되며 아마도 어떤 식 으로든 그 정적 성을 체계화해야합니다.

엔티티 프레임 워크

"이제 우리는이 비디오 엔티티. 사랑스러운에 EntityKey 속성에서 사용 있기 때문에, 재산, 동영상 ID를 변경할 수 없다는 아름다운 EF 문제에 도착."

멋진가요? EF는 귀하가 귀하의 PK를 갱신하지 않도록 강요하지 않습니다. 생성 된 모델 안에는 키에 대한 세터 내부의 속성 변경 검사가 있습니다. 해결책은 생성 된 코드를 변경하는 것입니다. 모델 변동성에 따라 실용적이지는 않지만 옵션 일 수 있습니다.

+0

jfar : 답변 해 주셔서 감사합니다. 우선, AFAIK AutoMapper가 무엇을 말하고 있습니까? 나는 AutoMapper를 다음과 같이 말하고있다 : http://code.google.com/p/automapperhome/. PK 매핑에 관해서는 모든 매핑을 한 곳에서 정의하고 코드 전체에서 .CreateMap 문을 사용하여 코드를 처리하지 말아야합니다. 문제는 여기서 db에 새 레코드를 만들거나 내 db에서 레코드를 업데이트하는지에 따라 상황에 따라 DTO를 내 엔터티에 다른 방식으로 매핑해야한다는 것입니다. AutoMapper 자체에 대한 자세한 내용은 문자가 부족합니다 ... – jason

+1

자, Automapper는 DTO -> EF Entity를 사용하지 않으려 고했지만 EF -> DTO 만 사용하도록 의도되었습니다. 그렇다면 내 뷰와 컨트롤러에 사용 된 객체가 DTO 객체 일 때 EF 객체를 통해 데이터베이스를 어떻게 업데이트해야합니까? 나는 겸손 해하려고하지 않는다. 필자는 삽입과 업데이트를 처리하는 올바른 방법을 알아 내려고 노력하고 있지만 특정 데이터 액세스 구현에 내 애플리케이션을 연결하지는 않습니다. 나는 당신이 가진 제안에 대해 열려 있습니다. – jason

+0

AFAIK = 내가 아는 한, 더 명확하지 않은 것에 대해 미안하다. – jfar

0

나는 동일한 시나리오에 있습니다. 내가 가진 유일한 해결책은 DTO -> Entity의 매핑에서 PK 필드를 무시하는 것입니다.

이러한 규칙은 Automapper 구성하는 동안 다음의 코드에 의해 달성 될 수있다 : 내가 아는 한

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

을, EF를 얻을 수있는 유일한 방법은 분리 된 엔티티 엔티티로 DTO를 매핑 작동 SaveChanges 전에 DB로부터 얻었습니다 (예제에서와 같이). 기존 개체에

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()) 문 내에서 추가 검사를 포함해야합니다. 이것이 없으면 함수는 false를 반환하고 매핑이 작동하지 않습니다.