8

Doing a copy of the same entity type in an MVC app, but looking to ignore copying the primary key (doing an update to an existing entity). But setting the Id column to ignore in the map below is not working and the Id is being overwritten.

cfg.CreateMap<VendorContact, VendorContact>()
    .ForMember(dest => dest.Id, option => option.Ignore())
    .ForMember(dest => dest.CreatedById, option => option.Ignore())
    .ForMember(dest => dest.CreatedOn, option => option.Ignore())
    ; 

Executing the Map:

existingStratusVendorContact = Mapper.Map<VendorContact>(vendorContact);

Saw this other answer, but it appears I am doing that already.

UPDATE:

Fyi, I am creating my maps in the Global.asax like so:

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<VendorContact, VendorContact>()
        .ForMember(dest => dest.Id, option => option.Ignore())
        .ForMember(dest => dest.CreatedById, option => option.Ignore())
        .ForMember(dest => dest.CreatedOn, option => option.Ignore())
        ;  

});
Community
  • 1
  • 1
crichavin
  • 4,672
  • 10
  • 50
  • 95
  • `existingStratusVendorContact` is an existing object and you want to replace properties except `Id`, `CreatedById`, `CreatedOn`? or create a new one with this properties in default value? – Arturo Menchaca Mar 03 '16 at 23:34
  • Yes, the former. Updating an existing object except those 3 properties. – crichavin Mar 03 '16 at 23:59
  • Possible duplicate of [Automapper: Update property values without creating a new object](https://stackoverflow.com/questions/2374689/automapper-update-property-values-without-creating-a-new-object) – Michael Freidgeim Apr 15 '18 at 00:51

2 Answers2

5

Your issue is that you're not giving automapper the existing object. Automapper can absolutely do this.

Mapper.Map<VendorContact>(vendorContact, existingStratusVendorContact);

Should do what you want. You current code is creating a brand new object, and replacing existingStratusVendorContact with the entirely new object. The above code will take the existing object and update values, as you expected.

Thomas Boby
  • 778
  • 8
  • 22
  • Thanks. This seems like it is working, but then I get an error upon trying to save the existingStratusVendorContact. 'The operation failed: `The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. ...` When I view that entity upon save, it looks like all the foreign keys are populated in the debugger...so not sure what is happening. Something with how entity framework is handling things I suppose. – crichavin Mar 04 '16 at 22:18
  • Got It! My final issue was with how I was retrieving the entity to be updated. After I changed it to get it .AsNoTracking...it then worked. – crichavin Mar 04 '16 at 22:26
  • Adding AsNoTracking() will cause the entity to not be updated. – Michael Brown Mar 30 '23 at 20:45
1

UPDATE:

The problem is when you assign Mapper.Map<VendorContact>(vendorContact); to existingStratusVendorContact you are replacing the current value of the variable with the returned by Map() method, no matter what properties you are ignoring.

With Mapper.Map(source) you can project an object to a new object of other type copying properties according some conventions, but you are creating a new object.

In your code, you are creating a new object with Id, CreatedById and CreatedOn properties with its default value.

You can use Mapper.Map(source, destination) overload that does exactly what you want:

Mapper.Map<VendorContact>(vendorContact, existingStratusVendorContact);

ORIGINAL:

If you are creating your maps like this:

var cfg = new MapperConfiguration(c =>
{
    c.CreateMap<VendorContact, VendorContact>()
        .ForMember(dest => dest.Id, option => option.Ignore())
        .ForMember(dest => dest.CreatedById, option => option.Ignore())
        .ForMember(dest => dest.CreatedOn, option => option.Ignore());
});

You need to create a mapper with this configuration:

var mapper = cfg.CreateMapper();

And use it to map the objects:

var existingStratusVendorContact = mapper.Map<VendorContact>(vendorContact);

If you use the static class Mapper the default behavior is used and properties are mapped.

Arturo Menchaca
  • 15,783
  • 1
  • 29
  • 53
  • @ArturoMechaca Thanks Arturo. See my updated question which indicates how I am creating the map. How does this affect your answer? Also, this is how I was doing it in another project in my solution that is using AutoMapper 3. But this new project is using AutoMapper 4. So maybe there is a change in the prefered Map creation method/syntax? – crichavin Mar 03 '16 at 23:21
  • @ArturoMechaca This is wrong, see https://github.com/AutoMapper/AutoMapper/blob/develop/src/AutoMapper/Mapper.cs#L140 `Mapped destination object, same instance as the object` – Thomas Boby Mar 04 '16 at 11:05
  • @ChadRichardson: found a way to do it with Automapper. thanks to Tomas – Arturo Menchaca Mar 04 '16 at 14:30