Skip to content

Commit 231c0fe

Browse files
authored
chore: Merge pull request #945 from DocSvartz/Refactoring-fix-#903-and-Fix-#943
Refactoring fix #903 and fix #943
2 parents 1d89074 + a87a5f8 commit 231c0fe

5 files changed

Lines changed: 57 additions & 29 deletions

File tree

src/Mapster.Tests/WhenCtorNullableParamMapping.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.VisualStudio.TestTools.UnitTesting;
22
using Shouldly;
3+
using System.Collections.Generic;
34

45
namespace Mapster.Tests
56
{
@@ -60,6 +61,27 @@ public void Dto_To_Domain_AbstractClassNull_MapsCorrectly()
6061
}
6162

6263

64+
/// <summary>
65+
/// https://github.com/MapsterMapper/Mapster/issues/943
66+
/// </summary>
67+
[TestMethod]
68+
public void NullableCtorPropagationCurrentWorkWithDestinationTransform()
69+
{
70+
var config = new TypeAdapterConfig();
71+
72+
config.Default
73+
.AddDestinationTransform(DestinationTransform.EmptyCollectionIfNull);
74+
75+
// Arrange
76+
var fooDto = new FooDto943();
77+
78+
// Act
79+
var foo = fooDto.Adapt<Foo943>(config);
80+
81+
// Assert
82+
foo.Strings.ShouldNotBeNull();
83+
}
84+
6385
#region Immutable classes with private setters, map via ctors
6486
private abstract class AbstractDomainTestClass
6587
{
@@ -96,6 +118,13 @@ public DomainTestClass(
96118
#endregion
97119

98120
#region DTO classes
121+
122+
class FooDto943
123+
{
124+
public string[] Strings { get; set; }
125+
}
126+
127+
record Foo943(List<string> Strings);
99128
private abstract class AbstractDtoTestClass
100129
{
101130
public string AbstractProperty { get; set; }

src/Mapster/Adapters/BaseAdapter.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ protected virtual Expression CreateInstantiationExpression(Expression source, Ex
448448
}
449449
}
450450

451-
private static Expression CreateAdaptExpressionCore(Expression source, Type destinationType, CompileArgument arg, MemberMapping? mapping = null, Expression? destination = null)
451+
internal static Expression CreateAdaptExpressionCore(Expression source, Type destinationType, CompileArgument arg, MemberMapping? mapping = null, Expression? destination = null)
452452
{
453453
var mapType = arg.MapType == MapType.MapToTarget && destination == null ? MapType.Map :
454454
mapping?.UseDestinationValue == true ? MapType.MapToTarget :
@@ -501,10 +501,24 @@ internal Expression CreateAdaptExpression(Expression source, Type destinationTyp
501501

502502
//adapt(_source);
503503
var notUsingDestinationValue = mapping is not { UseDestinationValue: true };
504-
var exp = _source.Type == destinationType && arg.Settings.ShallowCopyForSameType == true && notUsingDestinationValue
505-
&& rule == null
506-
? _source
507-
: CreateAdaptExpressionCore(_source, destinationType, arg, mapping, destination);
504+
Expression exp;
505+
506+
if (_source.Type == destinationType && arg.Settings.ShallowCopyForSameType == true
507+
&& notUsingDestinationValue && rule == null)
508+
exp = _source;
509+
else if (source is ConditionalExpression cond && mapping != null)
510+
{
511+
// convert ApplyNullable Propagation for NotPrimitive Nullable types
512+
if (mapping.Getter.Type.IsNotPrimitiveNullableType() && !mapping.DestinationMember.Type.IsNullable())
513+
{
514+
var adapt = CreateAdaptExpressionCore(cond.IfTrue.GetNotPrimitiveNullableValue(), mapping.DestinationMember.Type, arg, mapping);
515+
exp = Expression.Condition(cond.Test, adapt, mapping.DestinationMember.Type.CreateDefault());
516+
}
517+
else
518+
exp = CreateAdaptExpressionCore(_source, destinationType, arg, mapping, destination);
519+
}
520+
else
521+
exp = CreateAdaptExpressionCore(_source, destinationType, arg, mapping, destination);
508522

509523
//transform(adapt(_source));
510524
if (notUsingDestinationValue)

src/Mapster/Adapters/BaseClassAdapter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ protected Expression CreateInstantiationExpression(Expression source, ClassMappi
247247
}
248248
else
249249
getter = member.Getter
250-
.ApplyNullPropagationFromCtor(CreateAdaptExpression(member.Getter, member.DestinationMember.Type, arg, member), arg);
250+
.ApplyNullPropagationFromCtor(CreateAdaptExpressionCore(member.Getter, member.DestinationMember.Type, arg, member), arg);
251251

252252

253253
if (member.Ignore.Condition != null)

src/Mapster/Adapters/ClassAdapter.cs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,7 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
114114
? member.DestinationMember.GetExpression(destination)
115115
: null;
116116

117-
Expression adapt;
118-
119-
// convert ApplyNullable Propagation for NotPrimitive Nullable types
120-
if (member.Getter is ConditionalExpression cond && member.Getter.Type.IsNotPrimitiveNullableType()
121-
&& !member.DestinationMember.Type.IsNullable())
122-
{
123-
var value = CreateAdaptExpression(cond.IfTrue.GetNotPrimitiveNullableValue(), member.DestinationMember.Type, arg, member, destMember);
124-
adapt = Expression.Condition(cond.Test, value, member.DestinationMember.Type.CreateDefault());
125-
}
126-
else
127-
adapt = CreateAdaptExpression(member.Getter, member.DestinationMember.Type, arg, member, destMember);
117+
var adapt = CreateAdaptExpression(member.Getter, member.DestinationMember.Type, arg, member, destMember);
128118

129119
if (member.UseDestinationValue
130120
&& member.DestinationMember.Type.IsMapsterImmutable()
@@ -262,17 +252,7 @@ private static Expression SetValueByReflection(MemberMapping member, MemberExpre
262252
if (member.DestinationMember.SetterModifier == AccessModifier.None)
263253
continue;
264254

265-
Expression value;
266-
267-
// convert ApplyNullable Propagation for NotPrimitive Nullable types
268-
if (member.Getter is ConditionalExpression cond && member.Getter.Type.IsNotPrimitiveNullableType()
269-
&& !member.DestinationMember.Type.IsNullable())
270-
{
271-
var adapt = CreateAdaptExpression(cond.IfTrue.GetNotPrimitiveNullableValue(), member.DestinationMember.Type, arg, member);
272-
value = Expression.Condition(cond.Test, adapt, member.DestinationMember.Type.CreateDefault());
273-
}
274-
else
275-
value = CreateAdaptExpression(member.Getter, member.DestinationMember.Type, arg, member);
255+
var value = CreateAdaptExpression(member.Getter, member.DestinationMember.Type, arg, member);
276256

277257
//special null property check for projection
278258
//if we don't set null to property, EF will create empty object

src/Mapster/Utils/ExpressionEx.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,12 @@ public static Expression ApplyNullPropagationFromCtor(this Expression getter, Ex
483483
if (condition == null)
484484
return adapt;
485485

486-
return Expression.Condition(condition, adapt, adapt.Type.CreateDefault());
486+
// add supporting DestinationTransforms
487+
var transform = arg.Settings.DestinationTransforms.Find(it => it.Condition(adapt.Type));
488+
if (transform != null)
489+
return transform.TransformFunc(adapt.Type).Apply(arg.MapType, Expression.Condition(condition, adapt, Expression.Default(adapt.Type)));
490+
491+
return Expression.Condition(condition, adapt, Expression.Default(adapt.Type));
487492
}
488493

489494
public static string? GetMemberPath(this LambdaExpression lambda, bool firstLevelOnly = false, bool noError = false)

0 commit comments

Comments
 (0)