AgileMapper icon indicating copy to clipboard operation
AgileMapper copied to clipboard

Mapping from Optional fields to non optional fields

Open larsbloch opened this issue 3 years ago • 4 comments

Hello

I am creating a graphql project where you often use a Optional keyword. Somehow it works with your mapper but not with datetime and other complex types

From these "records"

public record NewCustomerInput(Optional<string> AuthId, string FirstName, string LastName, string Email, Optional<DateTime?> BirthDate, Optional<List<NewCustomerAddress>> Addresses);

public record NewCustomerAddress(string StreetName, string StreetNumber, string Zipcode, Optional<string> City, Optional<string> Floor, Optional<string> Door);

To

public class Customer
{ 
	public string AuthId { get; set; }
	public string FirstName { get; set; }
	public string LastName { get; set; }
	public string Email { get; set; }
	public DateTime? BirthDate { get; set; }

	public List<Address> Addresses { get; set; }
}

Doing this will allways make the birthdate and address list null. The simple fields like string, ints works fine but not lists, objects and datetimes:

public Customer CreateCustomer(IResolverContext context, NewCustomerInput input)
{
	var customer = Mapper.Map(input).ToANew<Customer>();

Removing the Optional from the birthdate and list input fields will populate the destination fields.

My current workaround is to populate those fields individually. The datetime will fail due to a nullreferenceException so I map that one manually. I can even remove mappings from optionals that does not have a value which is awesome.

public Customer CreateCustomer(IResolverContext context, NewCustomerInput input)
{
	Mapper.WhenMapping.IgnoreSources(c => c.If<Optional<object>>(s => s.HasValue == false));
	var customer = Mapper.Map(input).ToANew<Customer>();
	customer.BirthDate = input.BirthDate;
	customer.Addresses = Mapper.Map(input.Addresses.Value).ToANew<List<Address>>();

Is there anyway I can make your mapper support Optionals or do I maybe have to code my own mapper. Is there some setting I'm not aware of?

larsbloch avatar Nov 20 '21 21:11 larsbloch

Hi,

Thanks for letting me know about this! It looks from your code like Optional<T> is a GraphQL type, but I can't find anything on it - could you send me a link me to it?

Cheers,

Steve

SteveWilkes avatar Nov 21 '21 08:11 SteveWilkes

Hello again!

I've got a working dotnetfiddle here, but I am having to tell the mapper to map each Optional.Value property to its target, which is a shame.

This configuration (and an equivalent one for Addresses) should work, but doesn't:

Mapper.WhenMapping
    .From<Optional<DateTime?>>().To<DateTime?>()
    .Map((o, _) => o.Value).ToTargetInstead();

...so I'll look into that. Hopefully the work-around is good enough for now!

SteveWilkes avatar Nov 21 '21 12:11 SteveWilkes

There arent an official implementation of "Optional" but all have the "value" and "hasValue" as you have in your fiddle.

I think this is an awesome workaround.

Is the optional something that could be implemented or is it out of scope of your mapper ? Let me know if you more info or help from me.

larsbloch avatar Nov 21 '21 18:11 larsbloch

The ToTargetInstead() configuration should work, and would be a better solution as you'd only have to configure it once per optional type. I'll leave this issue open to track the bug.

Thanks! Steve

SteveWilkes avatar Nov 22 '21 18:11 SteveWilkes