MapsterMapper / Mapster

A fast, fun and stimulating object to object Mapper
MIT License
4.3k stars 328 forks source link

How to properly map to existing collections? #546

Open rm-code opened 1 year ago

rm-code commented 1 year ago

Let's say I have a situation where an incoming collections needs to be mapped onto an existing collection. src.Adapt(dest) doesn't produce the intended outcome since (I assume) Mapster doesn't know how to match the items in the collection.

using Mapster;
using MapsterTest;
using System.Text.Json;

var collection = new List<NestedCollectionEntity> {
  new NestedCollectionEntity
  {
    Id = 1,
    Value = "NestedCollectionEntity",
    CreatedOn = DateTime.Now,
    CreatedBy = "Me"
  }
};
var dtoCollection = new List<NestedCollectionDto> {
  new NestedCollectionDto
  {
    Id = 1,
    Value = "NestedCollectionDto",
  },
  new NestedCollectionDto
  {
    Id = 2,
    Value = "NestedCollectionDto",
  }
};

Console.WriteLine(JsonSerializer.Serialize(collection, new JsonSerializerOptions { WriteIndented = true }));

dtoCollection.Adapt(collection);

Console.WriteLine("After Mapping");
Console.WriteLine(JsonSerializer.Serialize(collection, new JsonSerializerOptions { WriteIndented = true }));

The output this produces looks like this:

[
  {
    "Id": 1,
    "Value": "NestedCollectionEntity",
    "CreatedOn": "2023-02-17T09:43:38.8157027+01:00",
    "CreatedBy": "Me"
  }
]

After Mapping
[
  {
    "Id": 1,
    "Value": "NestedCollectionDto",
    "CreatedOn": "0001-01-01T00:00:00",
    "CreatedBy": null
  },
  {
    "Id": 2,
    "Value": "NestedCollectionDto",
    "CreatedOn": "0001-01-01T00:00:00",
    "CreatedBy": null
  }
]

Is there an easy way to set this up via Mapster?

My current workaround is to write my own "matching logic":


foreach(var dto in dtoCollection)
{
  var match = collection.FirstOrDefault(o => o.Id == dto.Id);
  if (match != null)
  {
    dto.Adapt(match);
  }
  else
  {
    var n = dto.Adapt<NestedCollectionEntity>();
    collection.Add(n);
  }
}
andrerav commented 1 year ago

Possible duplicate of #537

DocSvartz commented 11 months ago

Hello, The collection adapter does not interact with elements of the collection TDistination Its logic For is approximately as follows:

 var _result = new Collection<TDistination>();

 foreach (var item in Collection<TSourse>)
 {
     _result.Add(item.Adapt<TDistination>());
 }

 return _result;

You converted NestedCollectionDto => NestedCollectionEntity

Since the specified fields with such names in "CreatedOn" "CreatedBy" in NestedCollectionDto was not found in them they were assigned default values

DocSvartz commented 11 months ago

Hello, looks like you wanted to get .unionby() or .intersectby() between List Tsource and List TDistination ?