diff --git a/src/AutoMapper/Execution/ProxyGenerator.cs b/src/AutoMapper/Execution/ProxyGenerator.cs index 705f7d9cc0..d666217b3d 100644 --- a/src/AutoMapper/Execution/ProxyGenerator.cs +++ b/src/AutoMapper/Execution/ProxyGenerator.cs @@ -51,12 +51,11 @@ private static Type EmitProxy(TypeDescription typeDescription) var interfaceType = typeDescription.Type; var additionalProperties = typeDescription.AdditionalProperties; var propertyNames = string.Join("_", additionalProperties.Select(p => p.Name)); - string name = - $"Proxy{propertyNames}<{Regex.Replace(interfaceType.AssemblyQualifiedName ?? interfaceType.FullName ?? interfaceType.Name, @"[\s,]+", "_")}>"; + var typeName = $"Proxy_{interfaceType.FullName}_{propertyNames}_{typeDescription.GetHashCode()}"; var allInterfaces = new List { interfaceType }; allInterfaces.AddRange(interfaceType.GetTypeInfo().ImplementedInterfaces); - Debug.WriteLine(name, "Emitting proxy type"); - TypeBuilder typeBuilder = proxyModule.DefineType(name, + Debug.WriteLine(typeName, "Emitting proxy type"); + TypeBuilder typeBuilder = proxyModule.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public, typeof(ProxyBase), interfaceType.IsInterface() ? new[] { interfaceType } : new Type[0]); ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, @@ -176,7 +175,11 @@ public TypeDescription(Type type) : this(type, PropertyDescription.Empty) public TypeDescription(Type type, IEnumerable additionalProperties) { Type = type ?? throw new ArgumentNullException(nameof(type)); - AdditionalProperties = additionalProperties?.ToArray() ?? throw new ArgumentNullException(nameof(additionalProperties)); + if(additionalProperties == null) + { + throw new ArgumentNullException(nameof(additionalProperties)); + } + AdditionalProperties = additionalProperties.OrderBy(p => p.Name).ToArray(); } public Type Type { get; } diff --git a/src/AutoMapper/QueryableExtensions/ExpressionBuilder.cs b/src/AutoMapper/QueryableExtensions/ExpressionBuilder.cs index 35fa7463fd..bada7f7c1d 100644 --- a/src/AutoMapper/QueryableExtensions/ExpressionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ExpressionBuilder.cs @@ -504,14 +504,14 @@ public override QueryExpressions GetSubQueryExpression(ExpressionBuilder builder MapFromSource = path.PropertyMaps.Take(path.PropertyMaps.Length - 1).Select(pm=>pm.SourceMember).MemberAccesses(instanceParameter), Property = new PropertyDescription ( - string.Join("_", path.PropertyMaps.Select(pm => pm.DestinationProperty.Name)), + string.Join("#", path.PropertyMaps.Select(pm => pm.DestinationProperty.Name)), path.Last.SourceType ), Marker = path.Marker }).ToArray(); - var letProperties = letMapInfos.Select(m => m.Property); - var letType = ProxyGenerator.GetSimilarType(request.SourceType, letProperties); + var properties = letMapInfos.Select(m => m.Property).Concat(GetMemberAccessesVisitor.Retrieve(projection, instanceParameter)); + var letType = ProxyGenerator.GetSimilarType(typeof(object), properties); var typeMapFactory = new TypeMapFactory(); TypeMap firstTypeMap; lock(_configurationProvider) @@ -539,9 +539,37 @@ void ReplaceSubQueries() } } + class GetMemberAccessesVisitor : ExpressionVisitor + { + private readonly Expression _target; + + public List Members { get; } = new List(); + + public GetMemberAccessesVisitor(Expression target) + { + _target = target; + } + + protected override Expression VisitMember(MemberExpression node) + { + if(node.Expression == _target) + { + Members.Add(node.Member); + } + return base.VisitMember(node); + } + + public static IEnumerable Retrieve(Expression expression, Expression target) + { + var visitor = new GetMemberAccessesVisitor(target); + visitor.Visit(expression); + return visitor.Members.Select(member => new PropertyDescription(member.Name, member.GetMemberType())); + } + } + class ReplaceMemberAccessesVisitor : ExpressionVisitor { - Expression _oldObject, _newObject; + private readonly Expression _oldObject, _newObject; public ReplaceMemberAccessesVisitor(Expression oldObject, Expression newObject) { diff --git a/src/IntegrationTests/CustomMapFrom/MapObjectPropertyFromSubQuery.cs b/src/IntegrationTests/CustomMapFrom/MapObjectPropertyFromSubQuery.cs index f7bf24adde..74061d1247 100644 --- a/src/IntegrationTests/CustomMapFrom/MapObjectPropertyFromSubQuery.cs +++ b/src/IntegrationTests/CustomMapFrom/MapObjectPropertyFromSubQuery.cs @@ -8,6 +8,7 @@ namespace AutoMapper.IntegrationTests { + using System.ComponentModel.DataAnnotations.Schema; using System.Linq.Expressions; using QueryableExtensions; @@ -162,6 +163,8 @@ public partial class Product public bool ECommercePublished { get; set; } public virtual ICollection
Articles { get; set; } public int Value { get; } + [NotMapped] + public int NotMappedValue { get; set; } public virtual List
OtherArticles { get; } }