Mapster
Mapster copied to clipboard
Mapping Optional<T> to T
I have a situation where I only want the Source.Name
property to be mapped to the Target.Name
property if the HasValue
flag of the Source.Name
property is true
.
struct Optional<T> {
public bool HasValue { get; }
public T? Value { get; }
}
class Source {
public Optional<string?> Name { get; set; }
}
class Target {
public string Name { get; set; }
}
I've tried to create a custom mapping using the TypeAdapterConfig
object as shown below, but the Target.Name
property never gets a value.
public void Register(TypeAdapterConfig config)
{
config
.NewConfig<Optional<string?>, string>()
.MapToTargetWith((source, target) => source.HasValue ? source.Value : target);
}
Here's the code I'm using to adapt the source object to a target object:
var target = new Source { Name = new Optional<string?>("John") }.Adapt<Target>();
I have so incredibly many source and target types that I dont want to explicitly create manual mapping for all the types, but in stead tell Mapster that when it encounters a property on a source class with the type of Optional<T>
, only map it if the HasValue
flag is true
.
I am doing this a part of my HotChocolate GraphQL API, here is a link to the documentation regarding Optional properties.
I have asked a similar question on hotchocolates slack channel the other day. I have yet to receive something usefull. If we can figure this out i will share it with the rest of the project. I think many people could take advantage of this usecase !
With AutoMapper you can do the following to add a type conversion, and it works great. However I was hoping to use Mapster as it is significantly faster.
config
.CreateMap<Optional<T>, T>()
.ConvertUsing((s, d) => s.HasValue ? s.Value : d)
The problem seems to be related to Nullable<T>
as it works perfectly fine when none of the source or target T
is Nullable<T>
eg: .NewConfig<Optional<string>, string>()
Hello, String is the same Class, what member do you want to replace with a string or this just stated as an example?
Sorry, I misunderstood the question. I thought you were looking for a solution to the fact that the update TDistination has null When null was not transmitted TSource.
Hello, problem in this. In this example, the conversion to a primitive. The primitive adapter does not support custom mapping processing. In this sample in to destination set value from method .ToString() Source object, not from source.Value. MapToTargetWith() doesn't work.
You @furier were right if Tsource == null && map != Projection working this section and return default(TDistination)
If this not work from not primitive class please add a sample.
Hello, probably it you want IgnorIF
Hello @furier, The underlying problem here is that .MapToTargetWith() only works when you are updating existing instances of your objects:
_Optional<string> _Optional = new();
Target _target = new();
_Optional.adapt(_target);
in this case .MapToTargetWith() not work:
var target = new Source { Name = new Optional<string?>("John") }.Adapt<Target>();
I get behavior you want from primitive type, you wanted to get this for all types ?
[TestMethod]
public void OptionalT()
{
TypeAdapterConfig<Optional561<string>, string>
.NewConfig()
.MapToTargetWith((source, target) => source.HasValue ? source.Value : target)
.MapToTargetPrimitive(true) // wip func
.IgnoreNullValues(true);
var sourceNull = new Source561 { Name = new Optional561<string?>(null) };
var target = new Source561 { Name = new Optional561<string>("John") }.Adapt<Target561>();
var TargetDestinationFromNull = new Target561() { Name = "Me" };
var NullOptionalUpdateTarget= sourceNull.Adapt(TargetDestinationFromNull); // Target.Name = "ME"
var _result = sourceNull.Adapt(target);
target.Name.ShouldBe("John");
}
class Optional561<T>
{
public Optional561(T? value)
{
if (value != null)
HasValue = true;
Value = value;
}
public bool HasValue { get; }
public T? Value { get; }
}
class Source561
{
public Optional561<string?> Name { get; set; }
}
class Target561
{
public string? Name { get; set; }
}