Home > Software design >  How to preserve the not mapped properties of a collection in a destination object with Automapper?
How to preserve the not mapped properties of a collection in a destination object with Automapper?

Time:12-13

Initial Situation: I have a source and a destination object and both have a collection of Elements. With Automapper I map the source to the destination object. After that, I add information to properties which are only present on the destination object (ItemName and ItemNumber). Additionally, I add information to the property Text of the objects in the collection AssetElementDto. After that, I call mapper.Map(source_update, destination); to update the destination object.

Question: When I run the code the information of ItemName and ItemNumber is preserved after the update. What can I do that also the information of the AssetElementDto of Text is preserved?

using AutoMapper;
using System.Runtime.InteropServices;

public class Program
{
    static void Main(string[] arg)
    {
        var config = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<Source, Destination>().PreserveReferences();
            cfg.CreateMap<AssetElement, AssetElementDto>().PreserveReferences();
        });
        var mapper = new Mapper(config);

        var source = new Source()
        {
            Name = "Sinonis",
            Id = new Random().Next(),
            Elements = new List<AssetElement>
            {
                new(){ Id = 1},
                new(){ Id = 2}
            }
        };

        var destination = mapper.Map<Destination>(source);
        destination.ItemNumber = 42;
        destination.Elements.ForEach(e => e.Text ="Wow");

        destination.ItemName = "NPC21";

        var source_update = new Source()
        {
            Name = "Nindalf",
            Id = new Random().Next(),
            Elements = new List<AssetElement>
            {
                new(){ Id = 3},
                new(){ Id = 4}
            }
        };

        Console.WriteLine($"Before update is: {destination.Name} {destination.Id} {destination.ItemNumber} {destination.ItemName}");
        destination.Elements.ForEach(e => Console.WriteLine($" {e.Id} {e.Text}"));

        mapper.Map(source_update, destination);

        Console.WriteLine($"After update is : {destination.Name} {destination.Id} {destination.ItemNumber} {destination.ItemName}");
        destination.Elements.ForEach(e => Console.WriteLine($" {e.Id} {e.Text}"));
    }
}

#region Source

public class Source
{
    public string Name;
    public int Id;

    public List<AssetElement> Elements;

}

public class AssetElement
{
    public int Id;
}

#endregion

#region Destination

public class Destination
{
    public string Name;
    public int Id;

    public List<AssetElementDto> Elements;

    public int ItemNumber;
    public string ItemName;
}

public class AssetElementDto
{
    public string Text;
    public int Id;
}

#endregion

Console Output:

Wow is not preserved after the update.

Before update is: Sinonis 1643275093 42 NPC21
 1 Wow
 2 Wow
After update is : Nindalf 75522068 42 NPC21
 3 null
 4 null

CodePudding user response:

Thank you Lucian Bargaoanu for this brief but powerful hint. This solved my problem. Please see the necessary changes in the code below. Here is the link to AutoMapper.Collection.

using AutoMapper;
using AutoMapper.EquivalencyExpression; //add using

public class Program
{
    static void Main(string[] arg)
    {
        var config = new MapperConfiguration(cfg =>
        {
            cfg.AddCollectionMappers(); //add the collection mapper
            cfg.CreateMap<Source, Destination>();
            cfg.CreateMap<AssetElement, AssetElementDto>().EqualityComparison((odto, o) => odto.Id == o.Id); //add the equality compersion
        });
        var mapper = new Mapper(config);

        var source = new Source()
        {
            Name = "Sinonis",
            Id = new Random().Next(),
            Elements = new List<AssetElement>
            {
                new(){ Id = 1},
                new(){ Id = 2}
            }
        };

        var destination = mapper.Map<Destination>(source);
        destination.ItemNumber = 42;
        destination.ItemName = "NPC21";
        destination.Elements.ForEach(e => e.Text ="Wow");

       

        var source_update = new Source()
        {
            Name = "Nindalf",
            Id = new Random().Next(),
            Elements = new List<AssetElement>
            {
                new(){ Id = 1},//ID's need to be the same as before
                new(){ Id = 2}
            }
        };

        Console.WriteLine($"Before update is: {destination.Name} {destination.Id} {destination.ItemNumber} {destination.ItemName}");
        destination.Elements.ForEach(e => Console.WriteLine($" {e.Id} {e.Text}"));

        mapper.Map(source_update, destination);

        Console.WriteLine($"After update is : {destination.Name} {destination.Id} {destination.ItemNumber} {destination.ItemName}");
        destination.Elements.ForEach(e => Console.WriteLine($" {e.Id} {e.Text}"));
    }
}

#region Source

public class Source
{
    public string Name;
    public int Id;

    public List<AssetElement> Elements;

}

public class AssetElement
{
    public int Id;
}


#endregion

#region Destination

public class Destination
{
    public string Name;
    public int Id;

    public List<AssetElementDto> Elements;

    public int ItemNumber;
    public string ItemName;
}

public class AssetElementDto
{
    public string Text;
    public int Id;
}

#endregion

Console:

Wow is preserved in the collection after the update.

Before update is: Sinonis 49772274 42 NPC21
 1 Wow
 2 Wow
After update is : Nindalf 236466397 42 NPC21
 1 Wow
 2 Wow
  • Related