Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use conditional mapping with different types of source field #673

Open
GTmAster opened this issue Feb 1, 2024 · 2 comments
Open

Comments

@GTmAster
Copy link

GTmAster commented Feb 1, 2024

For example there are 2 classes:

public class Source
{
    public int? IntValue { get; set; }
    public string StringValue { get; set; } = "Some Value";
}

public class Destination
{
    public string Mapped { get; set; } = string.Empty;
}

The task is put in Mapped string representation of IntValue if it's not null, otherwise use StringValue. I assume configuration should look like (according to Mapster docs):

TypeAdapterConfig.GlobalSettings
    .NewConfig<Source, Destination>()
    .Map(dest => dest.Mapped, src => src.IntValue, src => src.IntValue.HasValue)
    .Map(dest => dest.Mapped, src => src.StringValue);

But it gives runtime exception:

Mapster.CompileException: Error while compiling
source=Source
destination=Destination
type=Map
 ---> System.InvalidOperationException: No coercion operator is defined between types 'System.Nullable`1[System.Int32]' and 'System.String'.

Is it intended behavior or it's a bug? How to perform conditional mapping in given case Mapster way, without slapping .AfterMapping() and do it with custom code?

@stagep
Copy link

stagep commented Feb 1, 2024

The boolean conditional will be evaluated at runtime so the mapping when the int has a value needs to be defined to create a string from a nullable int.

TypeAdapterConfig.GlobalSettings
    .NewConfig<Source, Destination>()
    .Map(dest => dest.Mapped, src => src.IntValue.Value.ToString(), src => src.IntValue.HasValue)
    .Map(dest => dest.Mapped, src => src.StringValue);

@GTmAster
Copy link
Author

GTmAster commented Feb 1, 2024

Sad it's not possible. Because in real life it's not just int, string and .ToString().... it's a big hierarchy of POCO classes with their own async mapping configs with DI.

I was thinking that this config would be roughly compiled into something like:

if (conditionFunc1(src)) {
      destExpr.SetValue(srcExpr1.GetValue().Adapt<TDest>())
      return;
}
destExpr.SetValue(srcExpr2.GetValue().Adapt<TDest>())

But seems like it's not. guess no other way that put everything into .AfterMappingAsync():

.AfterMappingAsync(async (src, dest) => {
     var mapper = MapContext.Current.GetService<IAsyncMapper>();
     if (src => src.IntValue.HasValue) 
     {
           dest.Mapped = await mapper.AdaptToTypeAsync<string>(src.IntValue);
           return;
     }
     dest.Mapped = await mapper.AdaptToTypeAsync<string>(src.StringValue);
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants