Mapster icon indicating copy to clipboard operation
Mapster copied to clipboard

Multiple sources - Mapping required for every member

Open ChristopheLionet opened this issue 3 years ago • 5 comments

Issue https://github.com/MapsterMapper/Mapster/issues/180 shows how to solve the need for multiple sources using tuples, and that it is implemented in Mapster 5.0.

However, using multiple sources as stated in the docs introduces a heavy constraint, which is to map every member manually. In the following code, dto.CommonValue is null if not explicitly mapped in the config.

record PocoA(string SpecificValue);      
record PocoB(int CommonValue);                
record Dto(int CommonValue, int SumValue);  
//...

TypeAdapterConfig.GlobalSettings.NewConfig<(PocoA, PocoB), Dto>()                                                 
    .Map(dto => dto.SumValue, pocoTuple => pocoTuple.Item1.SpecificValue + pocoTuple.Item2.CommonValue);    
// ...

var dto = mapper.Map<(PocoA, PocoB), Dto>(pocoA, pocoB);  // dto.CommonValue is null

Is there a solution to this? It breaks the workflow in some large objects. If a single parameter needs an additional source, every single member needs to be mapped manually.

ChristopheLionet avatar Nov 29 '22 16:11 ChristopheLionet

Hi @ChristopheLionet, could you post a complete code sample please?

andrerav avatar Jan 04 '23 09:01 andrerav

I am also having this issue, though maybe I am not setting up the config correctly?

Code can be run here

using System;
using Mapster;
					
public class Program
{
	public static void Main()
	{
		
		TypeAdapterConfig<(Source1, Source2), Dest>.NewConfig()
                .Map(dest => dest, src => src.Item1)
                .Map(dest => dest, src => src.Item2);
		
		var src1 = new Source1{MyInt = 1};
		var src2 = new Source2{MyString = "Hello"};
		
		//Doesnt work
		var destTuple = Tuple.Create(src1, src2).Adapt<Dest>();
		
		//Works
		var destSrc1 = src1.Adapt<Dest>();
		var destSrc2 = src2.Adapt<Dest>();
		
		Console.WriteLine($"Tuple Mapping {destTuple.MyInt} {destTuple.MyString}");
		Console.WriteLine($"Regular Mapping src1 {destSrc1.MyInt} {destSrc1.MyString}");
		Console.WriteLine($"Regular Mapping src2 {destSrc2.MyInt} {destSrc2.MyString}");
	}
}

internal sealed class Source1 {
	public int MyInt {get; init;}
}

public class Source2 {
	public string MyString {get; init;}
}

public record Dest {
	public int MyInt {get; init;} 
	public string MyString {get; init;}
}

jackfrosty908 avatar Feb 20 '23 20:02 jackfrosty908

Hello @andrerav , @jackfrosty908

(Source1, Source2) is ValueTuple, not a Tuple

But Adapt in Record in this form is not work with RecordType fix

public record Dest {
	public int MyInt {get; init;} 
	public string MyString {get; init;}
}
 /// <summary>
 /// https://github.com/MapsterMapper/Mapster/issues/501
 /// </summary>
 [TestMethod]
 public void MultiplyTuple()
 {

     TypeAdapterConfig<(Source501, Dest501), DestRecord501>.NewConfig()
             .Map(dest => dest, src => src.Item1)
             .Map(dest => dest, src => src.Item2);

     var src1 = new Source501 { MyInt = 1 };
     var src2 = new Dest501 { MyString = "Hello" };

     //work
     var destTuple = ValueTuple.Create(src1, src2).Adapt<DestRecord501>();


     //Works
     var destSrc1 = src1.Adapt<DestRecord501>();
     var destSrc2 = src2.Adapt<DestRecord501>();
 }


 internal sealed class Source501
 {
     public int MyInt { get; init; }
 }

 public class Dest501
 {
     public string MyString { get; init; }
 }

 public record DestRecord501 (int MyInt, string MyString);

DocSvartz avatar Oct 21 '23 14:10 DocSvartz

@andrerav i Fix this bug in RecordAdapter. It will be ready along with the attribute for the legacy record description )

DocSvartz avatar Oct 23 '23 10:10 DocSvartz

That's awesome @DocSvartz! Please mention the issue number in the PR and I'll make sure that it's closed after merging :)

andrerav avatar Oct 23 '23 10:10 andrerav