Skip to content

System.ArgumentException -- incorrect Property access when using a subquery #4256

@MrZander

Description

@MrZander

Source/destination types

namespace MapRepro.Entities
{

    public class Foo
    {
        public int Id { get; set; }
        public int BarId { get; set; }

        public virtual Bar Bar { get; set; }
    }

    public class Bar
    {
        public Bar()
        {
            Foos = new HashSet<Foo>();
        }

        public int Id { get; set; }
        public int BazId { get; set; }

        public virtual Baz Baz { get; set; }
        public virtual ICollection<Foo> Foos { get; set; }
    }

    public class Baz
    {
        public Baz()
        {
            Bars = new HashSet<Bar>();
            Widgets = new HashSet<Widget>();
        }

        public int Id { get; set; }

        public virtual ICollection<Bar> Bars { get; set; }
        public virtual ICollection<Widget> Widgets { get; set; }
    }
    public partial class Widget
    {
        public int Id { get; set; }
        public int BazId { get; set; }

        public virtual Baz Baz { get; set; }
    }

}

namespace MapRepro.Models
{

    public class Foo
    {
        public int Id { get; set; }
        public int BarId { get; set; }
        public Bar MyBar { get; set; }
    }

    public class Bar
    {
        public int Id { get; set; }
        public int BazId { get; set; }
        public Baz MyBaz { get; set; }
    }

    public class Baz
    {
        public int Id { get; set; }
        public Widget FirstWidget { get; set; }
    }

    public class Widget
    {
        public int Id { get; set; }
        public int BazId { get; set; }
    }

}

Mapping configuration

    class TestProfile : Profile
    {
        public TestProfile()
        {
            CreateMap<Entities.Foo, Models.Foo>()
                .ForMember(f => f.Id, opts => opts.MapFrom(src => src.Id))
                .ForMember(f => f.BarId, opts => opts.MapFrom(src => src.BarId))
                .ForMember(f => f.MyBar, opts => opts.MapFrom(src => src.Bar))
            ;
            CreateMap<Entities.Bar, Models.Bar>()
                .ForMember(f => f.Id, opts => opts.MapFrom(src => src.Id))
                .ForMember(f => f.BazId, opts => opts.MapFrom(src => src.BazId))
                .ForMember(f => f.MyBaz, opts => opts.MapFrom(src => src.Baz))
            ;
            CreateMap<Entities.Baz, Models.Baz>()
                .ForMember(f => f.Id, opts => opts.MapFrom(src => src.Id))
                .ForMember(f => f.FirstWidget, opts => opts.MapFrom(src => src.Widgets.FirstOrDefault()))
            ;
            CreateMap<Entities.Widget, Models.Widget>()
                .ForMember(f => f.Id, opts => opts.MapFrom(src => src.Id))
                .ForMember(f => f.BazId, opts => opts.MapFrom(src => src.BazId))
            ;
        }
    }

//...

            var config = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile(new TestProfile());
            });
            config.AssertConfigurationIsValid();
            var mapper = config.CreateMapper();

Version: 12.0.1

EF Core 7.0.3
EF Core InMemory 7.0.3

Expected behavior

A valid mapping and successful projection

Actual behavior

An ArgumentException when AutoMapper tries to access a property to the wrong object.
As you can see by the exception below SubQueryPath.GetSourceExpression is trying to access the property Bar on the object Bar, which does not exist. Strangely, it only happens when projecting Foos, not when projecting Bars

System.ArgumentException
  HResult=0x80070057
  Message=Property 'MapRepro.Entities.Bar Bar' is not defined for type 'MapRepro.Entities.Bar' (Parameter 'property')
  Source=System.Linq.Expressions
  StackTrace:
   at System.Linq.Expressions.Expression.Property(Expression expression, PropertyInfo property)
   at System.Linq.Expressions.Expression.MakeMemberAccess(Expression expression, MemberInfo member)
   at System.Linq.Expressions.MemberExpression.Update(Expression expression)
   at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at AutoMapper.QueryableExtensions.Impl.ProjectionBuilder.FirstPassLetPropertyMaps.SubQueryPath.GetSourceExpression(Expression parameter)
   at AutoMapper.QueryableExtensions.Impl.ProjectionBuilder.FirstPassLetPropertyMaps.<>c__DisplayClass11_0.<GetSubQueryExpression>b__0(SubQueryPath path)
   at System.Linq.Enumerable.SelectListIterator`2.ToArray()
   at AutoMapper.QueryableExtensions.Impl.ProjectionBuilder.FirstPassLetPropertyMaps.GetSubQueryExpression(ProjectionBuilder builder, Expression projection, TypeMap typeMap, ProjectionRequest& request, ParameterExpression instanceParameter)
   at AutoMapper.QueryableExtensions.Impl.ProjectionBuilder.CreateProjection(ProjectionRequest& request, LetPropertyMaps letPropertyMaps)
   at AutoMapper.Internal.LockingConcurrentDictionary`2.<>c__DisplayClass2_1.<.ctor>b__1()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at AutoMapper.QueryableExtensions.Impl.ProjectionBuilder.GetProjection(Type sourceType, Type destinationType, Object parameters, MemberPath[] membersToExpand)
   at AutoMapper.QueryableExtensions.Extensions.ToCore(IQueryable source, Type destinationType, IConfigurationProvider configuration, Object parameters, IEnumerable`1 memberPathsToExpand)
   at AutoMapper.QueryableExtensions.Extensions.ToCore[TResult](IQueryable source, IConfigurationProvider configuration, Object parameters, IEnumerable`1 memberPathsToExpand)
   at MapRepro.Program.Main(String[] args) in C:\Users\alexander.DIVINELOGIC\source\repos\MapRepro\MapRepro\Program.cs:line 24

Steps to reproduce

See gist: https://gist.github.com/MrZander/0bcdd5a9b8b42e862b5b523b0d49002a

            var context = new ClientContext(new DbContextOptionsBuilder<ClientContext>().UseInMemoryDatabase("Test").Options);

            // Bar -> Baz -> Widgets.FirstOrDefault()  
            // OKAY
            var resultOkay = mapper.ProjectTo<Models.Bar>(context.Bars);

            // Foo -> Bar -> Baz -> Widgets.FirstOrDefault()
            // System.ArgumentException: 'Property 'MapRepro.Entities.Bar Bar' is not defined for type 'MapRepro.Entities.Bar' (Parameter 'property')'
            var resultNotOkay = mapper.ProjectTo<Models.Foo>(context.Foos);

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions