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 @@ -50,17 +50,17 @@ public void Build(List<LambdaExpression> memberSelectors, ParameterExpression pa

if (LogicBuilder.Expressions.Utils.TypeExtensions.IsLiteralType(memberType))
continue;

if (LogicBuilder.Expressions.Utils.TypeExtensions.IsList(memberType)
&& LogicBuilder.Expressions.Utils.TypeExtensions.IsLiteralType
(
LogicBuilder.Expressions.Utils.TypeExtensions.GetUnderlyingElementType(memberType)
TypeExtensions.GetUnderlyingElementType(memberType)
) == false)
{
List<LambdaExpression> childMemberSelectors = [];
ParameterExpression childParam = Expression.Parameter
(
LogicBuilder.Expressions.Utils.TypeExtensions.GetUnderlyingElementType(memberType),
TypeExtensions.GetUnderlyingElementType(memberType),
GetChildParameterName(param.Name)
);

Expand All @@ -76,7 +76,7 @@ public void Build(List<LambdaExpression> memberSelectors, ParameterExpression pa
(
typeof(Enumerable),
"Select",
[LogicBuilder.Expressions.Utils.TypeExtensions.GetUnderlyingElementType(selector), typeof(object)],
[TypeExtensions.GetUnderlyingElementType(selector), typeof(object)],
selector,
childSelector
),
Expand Down
10 changes: 5 additions & 5 deletions AutoMapper.AspNetCore.OData.EFCore/LinqExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ public static Expression GetSkipCall(this Expression expression, int? skip)
(
expression.Type.IsIQueryable() ? typeof(Queryable) : typeof(Enumerable),
"Skip",
new[] { expression.GetUnderlyingElementType() },
new[] { LogicBuilder.Expressions.Utils.TypeExtensions.GetUnderlyingElementType(expression) },
expression,
Expression.Constant(skip.Value)
);
Expand All @@ -412,7 +412,7 @@ public static Expression GetTakeCall(this Expression expression, int? top)
(
expression.Type.IsIQueryable() ? typeof(Queryable) : typeof(Enumerable),
"Take",
new[] { expression.GetUnderlyingElementType() },
new[] { LogicBuilder.Expressions.Utils.TypeExtensions.GetUnderlyingElementType(expression) },
expression,
Expression.Constant(top.Value)
);
Expand All @@ -433,15 +433,15 @@ public static Expression GetOrderByCountCall(this Expression expression, CountNo

public static Expression GetOrderByCountCall(this Expression expression, CountNode countNode, string methodName, ODataQueryContext context, string selectorParameterName = "a")
{
Type sourceType = expression.GetUnderlyingElementType();
Type sourceType = LogicBuilder.Expressions.Utils.TypeExtensions.GetUnderlyingElementType(expression);
ParameterExpression param = Expression.Parameter(sourceType, selectorParameterName);

Expression countSelector;

if (countNode.FilterClause is not null)
{
string memberFullName = countNode.GetPropertyPath();
Type filterType = sourceType.GetMemberInfoFromFullName(memberFullName).GetMemberType().GetUnderlyingElementType();
Type filterType = LogicBuilder.Expressions.Utils.TypeExtensions.GetUnderlyingElementType(sourceType.GetMemberInfoFromFullName(memberFullName).GetMemberType());
LambdaExpression filterExpression = countNode.FilterClause.GetFilterExpression(filterType, context);
countSelector = param.MakeSelector(memberFullName).GetCountCall(filterExpression);
}
Expand All @@ -465,7 +465,7 @@ public static Expression GetOrderByCountCall(this Expression expression, CountNo

public static Expression GetOrderByCall(this Expression expression, string memberFullName, string methodName, string selectorParameterName = "a")
{
Type sourceType = expression.GetUnderlyingElementType();
Type sourceType = LogicBuilder.Expressions.Utils.TypeExtensions.GetUnderlyingElementType(expression);
MemberInfo memberInfo = sourceType.GetMemberInfoFromFullName(memberFullName);
return Expression.Call
(
Expand Down
26 changes: 26 additions & 0 deletions AutoMapper.AspNetCore.OData.EFCore/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace AutoMapper.AspNet.OData
Expand Down Expand Up @@ -102,6 +103,31 @@ List<Type> DoLoad(List<Type> allTypes)

public static Dictionary<EdmTypeStructure, Type> GetEdmToClrTypeMappings() => Constants.EdmToClrTypeMappings;

public static Type GetUnderlyingElementType(this Type type)
{
TypeInfo typeInfo = type.GetTypeInfo();
if (typeInfo.IsArray)
return typeInfo.GetElementType();

if (!type.IsGenericType)
throw new ArgumentException(nameof(type));

Type[] genericArguments = type.GetGenericArguments();
Type genericTypeDefinition = type.GetGenericTypeDefinition();

if (genericTypeDefinition == typeof(IGrouping<,>))
return genericArguments[1];
else if (typeof(IDictionary<,>).IsAssignableFrom(genericTypeDefinition))
return typeof(KeyValuePair<,>).MakeGenericType(genericArguments[0], genericArguments[1]);
else if (genericArguments.Length == 1)
return genericArguments[0];
else
throw new ArgumentException(nameof(type));
}

public static Type GetUnderlyingElementType(this Expression expression)
=> GetUnderlyingElementType(expression.Type);

private class AssemblyResolver : IAssemblyResolver
{
private List<Assembly> _assemblides;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,16 @@ public static void SeedDatabase(AirVinylDbContext context)

context.DynamicVinylRecordProperties.Add(new DynamicProperty()
{
VinylRecordId = vinylRecords.First(r => r.Title == "Nevermind").VinylRecordId,//1,
VinylRecordId = vinylRecords.First(r => r.Title == "Nevermind").VinylRecordId,//1
Key = "Publisher",
Value = "Geffen"
});
context.DynamicVinylRecordProperties.Add(new DynamicProperty()
{
VinylRecordId = vinylRecords.First(r => r.Title == "Nevermind").VinylRecordId,//1
Key = "SomeData",
Value = new { TestProp = "value" }
});
context.SaveChanges();

context.DoorManufacturers.AddRange(
Expand Down
7 changes: 7 additions & 0 deletions AutoMapper.OData.EFCore.Tests/AirVinylModel/VinylLinkModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace AutoMapper.OData.EFCore.Tests.AirVinylModel
{
public class VinylLinkModel
{
public string Href { get; set; }
}
}
17 changes: 17 additions & 0 deletions AutoMapper.OData.EFCore.Tests/AirVinylModel/VinylRecordModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,22 @@ public class VinylRecordModel
= new List<DynamicPropertyModel>();

public IDictionary<string, object> Properties { get; set; }

private Dictionary<string, VinylLinkModel> _links;
public IDictionary<string, VinylLinkModel> Links {
get
{
if (_links is null)
{
_links = new Dictionary<string, VinylLinkModel>()
{
{ "buyingLink", new VinylLinkModel { Href = $"http://test/buy/{VinylRecordId}" } },
{ "reviewLink", new VinylLinkModel { Href = $"http://test/review/{VinylRecordId}" } }
};
}

return _links;
}
}
}
}
23 changes: 23 additions & 0 deletions AutoMapper.OData.EFCore.Tests/ExpansionTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using AutoMapper.AspNet.OData;
using AutoMapper.OData.EFCore.Tests.AirVinylData;
using AutoMapper.OData.EFCore.Tests.AirVinylModel;
using LogicBuilder.Expressions.Utils;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OData;
using Microsoft.AspNetCore.OData.Query;
Expand Down Expand Up @@ -42,6 +43,28 @@ void Test(ICollection<PersonModel> collection)
}
}

[Fact]
public async Task GetVinylRecordsExpandsComplexTypesByDefault()
{
string query = "/vinylrecordmodel";
Test(await GetAsync<VinylRecordModel, VinylRecord>(query));

void Test(ICollection<VinylRecordModel> collection)
{
Assert.True(collection.Count > 0);

//Navigation properties
Assert.True(collection.All(vinyl => vinyl.Person is null));
Assert.True(collection.All(vinyl => vinyl.PressingDetail is null));

//Complex types
Assert.Contains(collection, vinyl => vinyl.Properties.Count != 0);
Assert.Contains(collection, vinyl => vinyl.Properties.Any(p => !p.Value.GetType().IsLiteralType()));
Assert.Contains(collection, vinyl => vinyl.DynamicVinylRecordProperties.Count != 0);
Assert.Contains(collection, vinyl => vinyl.Links.Count != 0);
}
}

[Fact]
public async Task GetRecordStoresExpandsComplexTypesByDefault()
{
Expand Down
1 change: 1 addition & 0 deletions AutoMapper.OData.EFCore.Tests/Mappings/AirVinylMappings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public AirVinylMappings()
CreateMap<SpecializedRecordStore, SpecializedRecordStoreModel>()
.ForAllMembers(o => o.ExplicitExpansion());
CreateMap<VinylRecord, VinylRecordModel>()
.ForMember(dest => dest.Links, o => o.Ignore())
.ForAllMembers(o => o.ExplicitExpansion());
}
}
Expand Down