MapsterMapper / Mapster

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

Struggling with mapping readonly ICollection property #689

Open akordowski opened 7 months ago

akordowski commented 7 months ago

Discussed in https://github.com/MapsterMapper/Mapster/discussions/688

Originally posted by **akordowski** March 24, 2024 Hi everyone! I am currently struggling with the mapping of a readonly ICollection property. I followed the [instructions](https://github.com/MapsterMapper/Mapster/wiki/Mapping-readonly-prop) but I can't make it work. The readonly collection is not populated with the mapped content. What am I making wrong? Have anyone an idea how I can make it work? Here the code: **Programm.cs** ``` var config = TypeAdapterConfig.GlobalSettings; config.Scan(typeof(ChannelMapping).Assembly); config.Default.UseDestinationValue(m => m.SetterModifier == AccessModifier.None && m.Type.IsGenericType && m.Type.GetGenericTypeDefinition() == typeof(ICollection<>)); var channelSrc = new MapsterTest.Objects.Source.Channel { ChannelId = "123", Thumbnails = new MapsterTest.Objects.Source.ThumbnailDetails { Default = new MapsterTest.Objects.Source.Thumbnail { Url = "https://www.youtube.com/default.jpg" }, Medium = new MapsterTest.Objects.Source.Thumbnail { Url = "https://www.youtube.com/medium.jpg" }, High = new MapsterTest.Objects.Source.Thumbnail { Url = "https://www.youtube.com/high.jpg" } } }; // Thumbnails are mapped correctly to a collection var thumbnailsDest = channelSrc.Thumbnails.Adapt>().ToList(); // channelDest.Thumbnails collection is empty var channelDest = channelSrc.Adapt(); ``` **ThumbnailMapping.cs** ``` public class ThumbnailMapping : IRegister { public void Register(TypeAdapterConfig config) { config.ForType>() .MapWith(src => MapThumbnailDetails(src).ToList()); } private static IEnumerable MapThumbnailDetails(Objects.Source.ThumbnailDetails thumbnailDetails) { yield return MapThumbnail(thumbnailDetails.Default, "Default"); yield return MapThumbnail(thumbnailDetails.Medium, "Medium"); yield return MapThumbnail(thumbnailDetails.High, "High"); } private static Objects.Destination.Thumbnail MapThumbnail( Objects.Source.Thumbnail thumbnail, string thumbnailType) => new() { Type = thumbnailType, Url = thumbnail.Url.Trim(), }; } ``` **Channel.cs (Destination)** ``` public class Channel { public string ChannelId { get; set; } = default!; public ICollection Thumbnails { get; } = new List(); } ``` **Thumbnail.cs (Destination)** ``` public class Thumbnail { public string Type { get; set; } = default!; public string Url { get; set; } = default!; } ``` **Channel.cs (Source)** ``` public class Channel { public string ChannelId { get; set; } = default!; public ThumbnailDetails Thumbnails { get; set; } = default!; } ``` **ThumbnailDetails.cs (Source)** ``` public class ThumbnailDetails { public Thumbnail? Default { get; set; } public Thumbnail? Medium { get; set; } public Thumbnail? High { get; set; } } ``` **Thumbnail.cs (Source)** ``` public class Thumbnail { public string Url { get; set; } = default!; } ```
steingran commented 3 months ago

@akordowski I have the same issue. Did you ever find a solution?

This project is starting to look abandoned — no commits since September 2023, and no release since then. And issues opened are not answered... Is it time to move on to a different mapper?

akordowski commented 3 months ago

This is how I solved the problem. It's far from being an optimal solution but it works. It was a special case, but it might give you an idea. Hope it helps you.

public class SrcClassMapping : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config
            .ForType<DestClass, ICollection<SrcClass>>()
            .MapWith(src => MapCollection(src, null))
            .MapToTargetWith((src, dest) => MapCollection(src, dest));
    }

    private static ICollection<SrcClass> MapCollection(
        DestClass? destObj,
        ICollection<SrcClass>? srcCollection)
    {
        srcCollection ??= new List<SrcClass>();

        if (destObj is null)
            return srcCollection;

        // Custom mapping

        return srcCollection;
    }
}
steingran commented 3 months ago

@akordowski Great, thanks! Will give it a try