Skip to content

Commit

Permalink
Merge pull request #3187 from AutoMapper/enumerable-projections
Browse files Browse the repository at this point in the history
Match destination enumerable types with it's enumerable for LINQ
  • Loading branch information
jbogard committed Aug 9, 2019
2 parents 987e0e3 + ffc8e1f commit 53faf3f
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Linq;
using System.Linq.Expressions;
using AutoMapper.Configuration;
using AutoMapper.Mappers;
using AutoMapper.Mappers.Internal;

namespace AutoMapper.QueryableExtensions.Impl
Expand All @@ -29,17 +28,22 @@ private static MemberAssignment BindEnumerableExpression(IConfigurationProvider
{
return null;
}
expression = transformedExpressions.Aggregate(expression, (source, lambda) => Select(source, lambda));
expression = transformedExpressions.Aggregate(expression, Select);
}

expression = Expression.Call(typeof(Enumerable), propertyMap.DestinationType.IsArray ? "ToArray" : "ToList", new[] { destinationListType }, expression);
expression =
propertyMap.DestinationType.IsArray
? Expression.Call(typeof(Enumerable), nameof(Enumerable.ToArray), new[] {destinationListType}, expression)
: propertyMap.DestinationType.IsCollectionType()
? Expression.Call(typeof(Enumerable), nameof(Enumerable.ToList), new[] {destinationListType}, expression)
: expression;

return Expression.Bind(propertyMap.DestinationMember, expression);
}

private static Expression Select(Expression source, LambdaExpression lambda)
{
return Expression.Call(typeof(Enumerable), "Select", new[] { lambda.Parameters[0].Type, lambda.ReturnType }, source, lambda);
return Expression.Call(typeof(Enumerable), nameof(Enumerable.Select), new[] { lambda.Parameters[0].Type, lambda.ReturnType }, source, lambda);
}
}
}
89 changes: 89 additions & 0 deletions src/IntegrationTests/IEnumerableMemberProjections.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using Shouldly;
using Xunit;

namespace AutoMapper.IntegrationTests
{
using UnitTests;
using QueryableExtensions;
using System.Collections.Generic;

public class IEnumerableMemberProjections : AutoMapperSpecBase
{
public class Customer
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<Item> Items { get; set; }
}

public class Item
{
public int Id { get; set; }
public int Code { get; set; }
}

public class ItemModel
{
public int Id { get; set; }
public int Code { get; set; }
}

public class CustomerViewModel
{
public IEnumerable<ItemModel> Items { get; set; }
}

public class Context : DbContext
{
public Context()
{
Database.SetInitializer<Context>(new DatabaseInitializer());
}

public DbSet<Customer> Customers { get; set; }
}

public class DatabaseInitializer : DropCreateDatabaseAlways<Context>
{
protected override void Seed(Context context)
{
context.Customers.Add(new Customer
{
Id = 1,
FirstName = "Bob",
LastName = "Smith",
Items = new[] { new Item { Code = 1 }, new Item { Code = 3 }, new Item { Code = 5 } }
});

base.Seed(context);
}
}

public class CustomerItemCodes
{
public IEnumerable<int> ItemCodes { get; set; }
}

protected override MapperConfiguration Configuration => new MapperConfiguration(cfg =>
{
cfg.CreateMap<Customer, CustomerViewModel>();
cfg.CreateMap<Item, ItemModel>();
});

[Fact]
public void Can_map_to_ienumerable()
{
using (var context = new Context())
{
var result = ProjectTo<CustomerViewModel>(context.Customers).Single();

result.Items.Count().ShouldBe(3);
}
}
}
}

0 comments on commit 53faf3f

Please sign in to comment.