-
Notifications
You must be signed in to change notification settings - Fork 59
Expand file tree
/
Copy pathEFCoreLinqExtensions.cs
More file actions
71 lines (63 loc) · 3.63 KB
/
Copy pathEFCoreLinqExtensions.cs
File metadata and controls
71 lines (63 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using LogicBuilder.Expressions.Utils;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace AutoMapper.AspNet.OData
{
public static class EFCoreLinqExtensions
{
/// <summary>
/// Creates a list of Include expressions from a list of properties. Each property may include child and granchild properties.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="includes"></param>
/// <returns></returns>
public static ICollection<Expression<Func<IQueryable<T>, IIncludableQueryable<T, object>>>> BuildIncludesExpressionCollection<T>(this IEnumerable<string> includes) where T : class
=> (includes == null || includes.Count() == 0)
? null
: includes.Select(i => i.BuildIncludeExpression<T>()).ToList();
/// <summary>
/// Creates an Include expression from a property. The property may include child and granchild properties.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="includes"></param>
/// <returns></returns>
public static Expression<Func<IQueryable<T>, IIncludableQueryable<T, object>>> BuildIncludeExpression<T>(this string include) where T : class
{
if (string.IsNullOrEmpty(include)) return null;
ParameterExpression param = Expression.Parameter(typeof(IQueryable<T>), "q");
MethodCallExpression mce = param.GetInclude<T>(include);
return Expression.Lambda<Func<IQueryable<T>, IIncludableQueryable<T, object>>>(mce, param);
}
/// <summary>
/// Creates an include method call expression to be invoked on an expression e.g. (parameter, member, method call) of type IQueryable<T>.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="expression"></param>
/// <param name="includes"></param>
/// <param name="parameterName"></param>
/// <returns></returns>
public static MethodCallExpression GetInclude<TSource>(this Expression expression, string include)
{
if (string.IsNullOrEmpty(include)) return null;
ICollection<string> includes = include.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
Type parentType = typeof(TSource);
return includes.Aggregate(null, (MethodCallExpression mce, string next) =>
{
LambdaExpression selectorExpression = next.GetTypedSelector(parentType);
MemberInfo mInfo = parentType.GetMemberInfo(next);
mce = mce == null
//The Include espression takes two arguments. The parameter (object being extended by the helper method) and the lambda expression for the property selector
? Expression.Call(typeof(EntityFrameworkQueryableExtensions), "Include", new Type[] { parentType, mInfo.GetMemberType() }, expression, selectorExpression)
//The ThenInclude espression takes two arguments. The resulting method call expression from Include and the lambda expression for the property selector
: Expression.Call(typeof(EntityFrameworkQueryableExtensions), "ThenInclude", new Type[] { typeof(TSource), parentType, mInfo.GetMemberType() }, mce, selectorExpression);
parentType = mInfo.GetMemberType().GetCurrentType();//new previous property to include members from.
return mce;
});
}
}
}