Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AutoMapper.Collection.EntityFramework\AutoMapper.Collection.EntityFramework.csproj" />
</ItemGroup>
Expand Down
82 changes: 82 additions & 0 deletions src/AutoMapper.Collection.Tests/NullableIdTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.Collections.Generic;
using AutoMapper.EquivalencyExpression;
using FluentAssertions;
using Xunit;

namespace AutoMapper.Collection
{
public class NullableIdTests
{
[Fact]
public void Should_Work_With_Null_Id()
{
Mapper.Reset();
Mapper.Initialize(x =>
{
x.AddCollectionMappers();
x.CreateMap<ThingWithStringIdDto, ThingWithStringId>().EqualityComparison((dto, entity) => dto.ID == entity.ID);
});

var original = new List<ThingWithStringId>
{
new ThingWithStringId { ID = "1", Title = "test0" },
new ThingWithStringId { ID = "2", Title = "test2" },
};

var dtos = new List<ThingWithStringIdDto>
{
new ThingWithStringIdDto { ID = "1", Title = "test0" },
new ThingWithStringIdDto { ID = "2", Title = "test2" },
new ThingWithStringIdDto { Title = "test3" }
};

Mapper.Map(dtos, original);

original.Should().HaveSameCount(dtos);
}


[Fact]
public void Should_Work_With_Multiple_Null_Id()
{
Mapper.Reset();
Mapper.Initialize(x =>
{
x.AddCollectionMappers();
x.CreateMap<ThingWithStringIdDto, ThingWithStringId>().EqualityComparison((dto, entity) => dto.ID == entity.ID);
});

var original = new List<ThingWithStringId>
{
new ThingWithStringId { ID = "1", Title = "test0" },
new ThingWithStringId { ID = "2", Title = "test2" },
new ThingWithStringId { ID = "3", Title = "test3" },
};

var dtos = new List<ThingWithStringIdDto>
{
new ThingWithStringIdDto { ID = "1", Title = "test0" },
new ThingWithStringIdDto { ID = "2", Title = "test2" },
new ThingWithStringIdDto { Title = "test3" },
new ThingWithStringIdDto { Title = "test4" },
};

Mapper.Map(dtos, original);

original.Should().HaveSameCount(dtos);
}

public class ThingWithStringId
{
public string ID { get; set; }
public string Title { get; set; }
public override string ToString() { return Title; }
}

public class ThingWithStringIdDto
{
public string ID { get; set; }
public string Title { get; set; }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using AutoMapper.Collection;
Expand All @@ -16,30 +15,30 @@ public static Type GetSinglePredicateExpressionArgumentType(this Type type)
{
return _singleParameterTypeDictionary.GetOrAdd(type, t =>
{
var isExpression = typeof (Expression).GetTypeInfo().IsAssignableFrom(t.GetTypeInfo());
var isExpression = typeof(Expression).GetTypeInfo().IsAssignableFrom(t.GetTypeInfo());
if (!isExpression)
return null;

var expressionOf = t.GetTypeInfo().GenericTypeArguments.First();
var isFunction = expressionOf.GetGenericTypeDefinition() == typeof (Func<,>);
var expressionOf = t.GetTypeInfo().GenericTypeArguments[0];
var isFunction = expressionOf.GetGenericTypeDefinition() == typeof(Func<,>);
if (!isFunction)
return null;

var isPredicate = expressionOf.GetTypeInfo().GenericTypeArguments[1] == typeof (bool);
var isPredicate = expressionOf.GetTypeInfo().GenericTypeArguments[1] == typeof(bool);
if (!isPredicate)
return null;

var objType = expressionOf.GetTypeInfo().GenericTypeArguments.First();
var objType = expressionOf.GetTypeInfo().GenericTypeArguments[0];
return CacheAndReturnType(type, objType);
});
}

private static Type CacheAndReturnType(Type type, Type objType)
{
_singleParameterTypeDictionary.AddOrUpdate(type, objType, (t,t2) => objType);
_singleParameterTypeDictionary.AddOrUpdate(type, objType, (_, __) => objType);
return objType;
}

public static Expression<Func<T, int>> GetHashCodeExpression<T>(this List<Expression> members, ParameterExpression sourceParam)
{
var hashMultiply = Expression.Constant(397L);
Expand All @@ -48,20 +47,30 @@ public static Expression<Func<T, int>> GetHashCodeExpression<T>(this List<Expres
var returnTarget = Expression.Label(typeof(int));
var returnExpression = Expression.Return(returnTarget, Expression.Convert(hashVariable, typeof(int)), typeof(int));
var returnLabel = Expression.Label(returnTarget, Expression.Constant(-1));

var expressions = new List<Expression>();
foreach (var member in members)
{
var callGetHashCode = Expression.Call(member, member.Type.GetDeclaredMethod(nameof(GetHashCode)));
var convertHashCodeToInt64 = Expression.Convert(callGetHashCode, typeof(long));
// Call the GetHashCode method
var hasCodeExpression = Expression.Convert(Expression.Call(member, member.Type.GetDeclaredMethod(nameof(GetHashCode))), typeof(long));

// return (((object)x) == null ? 0 : x.GetHashCode())
var hashCodeReturnTarget = Expression.Label(typeof(long));
var hashCode = Expression.Block(
Expression.IfThenElse(
Expression.ReferenceEqual(Expression.Convert(member, typeof(object)), Expression.Constant(null)),
Expression.Return(hashCodeReturnTarget, Expression.Constant(0L, typeof(long))),
Expression.Return(hashCodeReturnTarget, hasCodeExpression)),
Expression.Label(hashCodeReturnTarget, Expression.Constant(0L, typeof(long))));

if (expressions.Count == 0)
{
expressions.Add(Expression.Assign(hashVariable, convertHashCodeToInt64));
expressions.Add(Expression.Assign(hashVariable, hashCode));
}
else
{
var oldHashMultiplied = Expression.Multiply(hashVariable, hashMultiply);
var xOrHash = Expression.ExclusiveOr(oldHashMultiplied, convertHashCodeToInt64);
var xOrHash = Expression.ExclusiveOr(oldHashMultiplied, hashCode);
expressions.Add(Expression.Assign(hashVariable, xOrHash));
}
}
Expand Down