views:

455

answers:

2

I just started using the Entity Framework 1.0 recently and believe I am beginning to feel the pains everyone is talking about. I'm trying to use best practices so I have a set of DTO that get mapped to and from my Entities via AutoMapper.

The real catch is when I'm trying to update an object. The first gotcha was that I could not find a way to create a new entity, transfer the data from my DTO, and still have the entity ObjectContext realize that it has been changed. I used the following code:

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

I then figured, perhaps I need to just grab the entity from the database first, attach to the context, call the Map method on Mapper, then call SaveChanges. Here what I did:

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

Now we get to the lovely EF issue of not being allowed to change the property, VideoId, because it's used by the EntityKey property on the Video entity. Lovely. I had setup the mappings so that when I mapped from my DTO to an EF Entity, the EntityKey property would get a value. Now I need a way to make an exception to that mapping rule, but have no clue where to begin. I suppose I could create a brand new Mapping rule right in this method and set the EntityKey & VideoId properties to be ignored, but that seems pretty sloppy. Furthermore, I'm not sure a mapping created at this point would stick. If it overrode the initial setup that allowed the DTO to map a value to the EntityKey on the entity, that would backfire in a whole different way.

Anyone have a better idea?

+2  A: 

AutoMapper

Your first problem is that as far as I know AutoMapper is not designed to go from DTO->Entity only Entity->DTO. This could have changed recently so I'm not really sure. See this link for more information about what automapper is designed to do: The case for two way mapping

PK Mapping

You say: "Mapping rule right in this method and set the EntityKey & VideoId properties to be ignored, but that seems pretty sloppy"

I don't think thats sloppy at all. You really shouldn't touch a EntityKey/PK after its been persisted and probably should codify its staticness in some way.

Entity Framework

"Now we get to the lovely EF issue of not being allowed to change the property, VideoId, because it's used by the EntityKey property on the Video entity. Lovely."

Lovely? EF is not forcing you to not update your PK. Inside the generated models there is a property change check inside the setter for your keys. The solution would be to change the generated code. Depending on your model volatility this may not be practical but it is an option.

jfar
jfar: Thanks for your response. First of all, what are you referring to by AFAIK AutoMapper? I'm referring to the AutoMapper here: http://code.google.com/p/automapperhome/. With respect to the PK Mapping, I'm talking about defining all mappings in one spot and not littering my code with .CreateMap statements throughout the code. The issue here is that I need to to circumstantially map my DTO to my Entity in different ways depending on if I'm creating a new record in my db or updating a record in my db. More on the AutoMapper itself in a second...running out of characters...
Jason
Okay, you mentioned that Automapper wasn't intended to go from DTO --> EF Entity, but was intended to be EF -> DTO only. If that was the case, how am I supposed to update my database via EF objects when the objects used in my view and controller are DTO objects? I'm not trying to be condescending or anything. I'm just trying to figure out the right way to handle inserts and updates, while not tying my application to a specific data access implementation. I'm open to any suggestions you might have.
Jason
AFAIK = as far as I know, sorry for not being clearer
jfar
I was looking over my open questions and saw this one. After reading your response AND the linked article (RTFM...I know...), things make a lot more sense. It was actually rather freeing to not force my DTO's to simply mimic conventions mandated by my Domain model. I realize there's a lot of filler I was putting in them that just didn't need to be there. Thanks for the informative response. Sorry it took me this long to "get it".
Jason
A: 

I'm in the same scenario. The only solution I got is to Ignore the PK field in the mapping from DTO -> Entity.

Such Rule can be achieved by the following line of code during the Automapper Configuration:

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

As far as I know, the only way to get EF works with Detached Entities is mapping the DTO to the Entity you got from DB before the SaveChanges (as you did in the example).

Bitbreaker