Entity Framework, AutoMapper, Updates for Entity Processing

I just recently started using Entity Framework 1.0 and I think I'm starting to feel the pain everyone is talking about. I am trying to use best practices, so I have a DTO set that maps to my objects and to my objects through AutoMapper.

The real catch is when I try to update an object. The first was that I could not find a way to create a new object, transfer data from my DTO, and still have an ObjectContext object that understands that it has been modified. 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 updated state context.SaveChanges(); //doesn't save the entity return pVideo; } 

Then I realized, maybe I just need to first grab the entity from the database, attach to the context, call the Map method on Mapper, and then call SaveChanges. Here is 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 move on to the beautiful EF problem when you are not allowed to change the VideoId property because it is used by the EntityKey property for the Video object. Beautiful. I configured the mappings, so when I mapped my DTO to EF Entity, the EntityKey property will get the value. Now I need a way to make an exception for this matching rule, but I don’t know where to start. I believe that I could create a completely new matching rule right in this method and set the EntityKey and VideoId properties that will be ignored, but that seems pretty messy. Also, I'm not sure what the creation created at this stage will adhere to. If he overrides the initial setting that allowed the DTO to map the EntityKey value on the object, this could have the opposite effect in a completely different way.

Anyone have a better idea?

+4
source share
5 answers

AutoMapper

Your first problem is that, as far as I know, AutoMapper is not designed to go from DTO-> Entity only Entity-> DTO. This may change recently, so I'm not sure. See this link for more information on what is intended for automapper: Case for two-way matching

PK Mapping

You say: "The matching rule in this method and set the EntityKey and VideoId properties to ignore, but that seems pretty messy."

I do not think it is careless. You really shouldn't touch EntityKey / PK after saving it, and probably should somehow codify your statics.

Entity Framework

"Now we move on to the beautiful EF problem when you are not allowed to change the VideoId property because it is used by the EntityKey property on the Video object. Lovely."

Beautiful? EF does not force you not to update your PC. Inside the generated models, there is a check for property changes 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.

+6
source

Try matching an existing object:

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

And save the Ignore () in place.

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

+3
source

This can help if you don't want to put .Ignore() on every object you want to map.

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

Essentially, you should configure AutoMapper to ignore all Entity properties that are not scalar:

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

Perhaps additional work can be added to avoid a reset if the property is PK (the property in the EdmScalarPropertyAttribute instance ( EntityKey == true? ) Reports this).

+1
source

I am in the same scenario. The only solution I got is to ignore the PK field when matching with DTO -> Entity.

Such a rule can be achieved with the following line of code during Automapper configuration:

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

As far as I know, the only way to get EF to work with Detached Entities is to map the DTO to Entity, which you got from the database to SaveChanges (as in the example).

0
source

Please note that the example provided by "Mauricio Morales" will only work if you do not use prefixes. If you use them, you need to slightly modify the code above, otherwise:

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

That is, you need to enable additional checks inside the if (!members.Any()) . Without this, the function return false and the mapping will not work.

0
source

Source: https://habr.com/ru/post/1299778/


All Articles