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

Mapping nullable Enum to custom object #640

Closed
WahidBitar opened this issue Oct 8, 2023 · 11 comments
Closed

Mapping nullable Enum to custom object #640

WahidBitar opened this issue Oct 8, 2023 · 11 comments

Comments

@WahidBitar
Copy link

for now I can have something like the following to register mapping for all enums in the system

config.NewConfig<Enum, KeyValueData>()
            .MapWith(s => new KeyValueData(s, Enums.ResourceManager));

However, it's not possible to have the same cofig for a nullable Enum.

The following config is not working:

config.NewConfig<Enum?, KeyValueData?>()
            .MapWith(s => s == null ? null : new KeyValueData(s.ToString(), Enums.ResourceManager));

I'll get the following Exception

Error while compiling
source=Tests.FirstClass
destination=Tests.SecondClass
type=Map
-> InnerException:
Error while compiling
source=System.Nullable`1[Model.IdentityType]
destination=Model.KeyValueData
type=Map
--> InnerException:
No default constructor for type 'KeyValueData', please use 'ConstructUsing' or 'MapWith'

@WahidBitar
Copy link
Author

I've figured a way out but still think it might be a better if we've somthing more helpful in the config. Especially from primitive types to classes. Anyways, my solution was simply like the following:

config.NewConfig(typeof(Nullable<>), typeof(KeyValueData))
            .IgnoreNullValues(true)
            .Map("key", "Value")
            .MapToConstructor(true);

@DocSvartz
Copy link

DocSvartz commented Oct 8, 2023

Hello @WahidBitar , if your goal is to skipped mapping when the TSource is null, maybe your help .IgnorIf()

@DocSvartz
Copy link

DocSvartz commented Oct 9, 2023

Hello @WahidBitar, I ran into this problem while preparing a fix for the problem record detection.

Please add sample Type of KeyValueData. To make it easier to understand which way the processing is going

@WahidBitar
Copy link
Author

Thanks @DocSvartz , My main goal is not to skip the null values. My goal is to map from a nullable enum to my custom class KeyValueData in a general way.
I'll put here the entire aspects and my work around so you may take benifit of it.

Note: you may found something weard in my KeyValueData class because I have a general mapper from Enum to string because I put translation of the enums in the Resources files, so If you don't have this case your config should be simpler. Anyway here is my classes and config:

Mapping config:

public class GeneralMapper : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        // by default the following config will cause the Key property in the KeyValueData to get the value from the resources.
        // so I've updated the KeyValueData class to ignore the setter
        config.ForType<Enum, string?>()
            .MapWith(e => Enums.ResourceManager.GetString(e.ToResourceKey()) ?? e.ToString());
        
        config.NewConfig<Enum, KeyValueData?>()
            .MapWith(s => new KeyValueData(s));
        
        config.NewConfig(typeof(Nullable<>), typeof(KeyValueData))
            .MapToConstructor(true)
            .Map("key", "Value");
    }
}

the KeyValueData class:

public record KeyValueData
{
    private readonly string? keyHolder; // I had to set this field to this name becuase key will get the value from Resources
    private string? description;

    public KeyValueData(Enum key)
    {
        this.keyHolder = key.ToString();
        Description = Enums.ResourceManager.GetString(key.ToResourceKey()) ?? key.ToResourceKey();
    }

    public string Key
    {
        get => keyHolder!;
        set { } // Don't know why mapster call the setter after calling the constructor. I guess there is a bug related to this.
    }

    public string? Description
    {
        get => description;
        set => description ??= value;
    }
}

@DocSvartz
Copy link

DocSvartz commented Oct 9, 2023

@WahidBitar, I wanted to see the KeyValueData in order to better help you.
But yes, it won't solve your main problem (
Now I see next:

  1. In this moment you Type KeyValueData has been detect Mapster as Class not as Record.
  2. Activate Setter from Property Key possible linked from this bug in Class adapter I described it from this issue Mapster.tool MapToConstructor reassigns a object property despite assigning it in the constructor  #633.

You use Record only as immutable type ? Or you used in this time mutable behavior from update.

Example:

_destination = new KeyValueData();
var result = _Input.adapt(_desination)
var checkresult = object.ReferenceEquals(_result, _desination) //  return true. _result is not modified copy _destination.

@DocSvartz
Copy link

DocSvartz commented Oct 10, 2023

Hello @WahidBitar , In version Mapster 7.4.0 and Mapster Tool 8.4.0 (Net 7.0) it working

from your last example: not Error

 public class GeneralMapper : IRegister
 {
     public void Register(TypeAdapterConfig config)
     {
         config.NewConfig<Enum?, KeyValueData?>()
         .MapWith(s => s == null ? null : new KeyValueData(s));
     }
}

Result of generation:

public partial class FooMapper : TEstConsole.Mapster.IFooMapper
{
    public TEstConsole.clases.KeyValueData MapToEntity(System.Enum s)
    {
        return s == null ? null : new TEstConsole.clases.KeyValueData(s);
    }
}


@WahidBitar
Copy link
Author

thank you so much @DocSvartz
till now I don't use the Mapster Tool, but I am using the Mapster 7.4.0 and don't know why this config didn't work for me

config.NewConfig<Enum?, KeyValueData?>()
            .MapWith(s => s == null ? null : new KeyValueData(s.ToString(), Enums.ResourceManager));

so I ended up with my workaround solution

@DocSvartz
Copy link

DocSvartz commented Oct 10, 2023

I get you Error Result. Try found problem :)

@DocSvartz
Copy link

DocSvartz commented Oct 13, 2023

@WahidBitar @andrerav

Looks like I made a fix from this problem.

@andrerav i can integrated this fix from my PR #634 or is it better to open a new PR?

Upd:
I'll open a new PR, I got a solution, but I don't like it :). Perhaps someone can improve it.

@andrerav
Copy link
Contributor

@DocSvartz Yes I prefer a separate PR :) Thanks for all your recent contributions, amazing work!

DocSvartz added a commit to DocSvartz/Mapster that referenced this issue Oct 15, 2023
andrerav added a commit that referenced this issue Jan 2, 2025
Fix to issue #640 - Nullable Emun to Nullable Destination (Class  or param)  - Need Sample for testing
@stagep
Copy link

stagep commented Jan 7, 2025

In order to identify issues that are still active, we are closing issues that we believe are either resolved or are dormant. If your issue is still active then please reopen. Thanks.

@stagep stagep closed this as completed Jan 7, 2025
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

4 participants