Skip to content

Commit c93c882

Browse files
committed
fix #309 fix EF Core with param
1 parent c21b773 commit c93c882

File tree

1 file changed

+58
-4
lines changed

1 file changed

+58
-4
lines changed

src/Mapster.EFCore/TypeAdapterBuilderExtensions.cs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Reflection;
77
using Mapster.EFCore;
88
using Microsoft.EntityFrameworkCore;
9+
using Microsoft.EntityFrameworkCore.Query;
910

1011
namespace Mapster
1112
{
@@ -42,7 +43,7 @@ public static TypeAdapterBuilder<TSource> EntityFromContext<TSource>(this TypeAd
4243
Expression.Convert(
4344
Expression.Property(
4445
Expression.Property(
45-
Expression.Property(null, current),
46+
Expression.Property(null, current!),
4647
nameof(MapContext.Parameters)),
4748
indexer,
4849
Expression.Constant(dbKey)),
@@ -55,7 +56,7 @@ public static TypeAdapterBuilder<TSource> EntityFromContext<TSource>(this TypeAd
5556
var setAssign = Expression.Assign(set, Expression.Call(db, setMethod));
5657

5758
var getters = keys.Select(key => arg.DestinationType.GetProperty(key))
58-
.Select(prop => new PropertyModel(prop))
59+
.Select(prop => new PropertyModel(prop!))
5960
.Select(model => arg.Settings.ValueAccessingStrategies
6061
.Select(s => s(src, model, arg))
6162
.FirstOrDefault(exp => exp != null))
@@ -67,7 +68,7 @@ public static TypeAdapterBuilder<TSource> EntityFromContext<TSource>(this TypeAd
6768
Expression find = Expression.Call(set, nameof(DbContext.Find), null,
6869
Expression.NewArrayInit(typeof(object), getters));
6970
if (arg.MapType == MapType.MapToTarget)
70-
find = Expression.Coalesce(find, dest);
71+
find = Expression.Coalesce(find, dest!);
7172
var ret = Expression.Coalesce(
7273
find,
7374
Expression.New(arg.DestinationType));
@@ -82,7 +83,60 @@ public static TypeAdapterBuilder<TSource> EntityFromContext<TSource>(this TypeAd
8283
public static IQueryable<TDestination> ProjectToType<TDestination>(this IAdapterBuilder<IQueryable> source)
8384
{
8485
var queryable = source.Source.ProjectToType<TDestination>(source.Config);
85-
return new MapsterQueryable<TDestination>(queryable, source);
86+
if (!source.HasParameter || source.Parameters.All(it => it.Key.StartsWith("Mapster.")))
87+
return new MapsterQueryable<TDestination>(queryable, source);
88+
89+
var call = (MethodCallExpression) queryable.Expression;
90+
var project = call.Arguments[1];
91+
var mapContext = typeof(MapContext);
92+
var current = mapContext.GetProperty(nameof(MapContext.Current), BindingFlags.Public | BindingFlags.Static);
93+
var properties = mapContext.GetProperty(nameof(MapContext.Parameters), BindingFlags.Public | BindingFlags.Instance);
94+
var item = typeof(Dictionary<string, object>)
95+
.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance)!
96+
.GetMethod;
97+
98+
var map = new Dictionary<Expression, Expression>();
99+
foreach (var (key, value) in source.Parameters)
100+
{
101+
if (key.StartsWith("Mapster."))
102+
continue;
103+
var currentEx = Expression.Property(null, current!);
104+
var propertiesEx = Expression.Property(currentEx, properties!);
105+
var itemEx = Expression.Call(propertiesEx, item!, Expression.Constant(key));
106+
107+
map.Add(itemEx, Parameterize(value).Body);
108+
}
109+
110+
var replaced = new ExpressionReplacer(map).Visit(project);
111+
var methodCallExpression = Expression.Call(call.Method, call.Arguments[0], replaced!);
112+
var replacedQueryable = queryable.Provider.CreateQuery<TDestination>(methodCallExpression);
113+
return new MapsterQueryable<TDestination>(replacedQueryable, source);
114+
}
115+
116+
private static Expression<Func<object>> Parameterize(object value)
117+
{
118+
return () => value;
119+
}
120+
}
121+
122+
internal class ExpressionReplacer : ExpressionVisitor
123+
{
124+
private readonly Dictionary<Expression, Expression> _map;
125+
126+
public ExpressionReplacer(Dictionary<Expression, Expression> map)
127+
{
128+
_map = map;
129+
}
130+
131+
public override Expression Visit(Expression node)
132+
{
133+
foreach (var (key, value) in _map)
134+
{
135+
if (ExpressionEqualityComparer.Instance.Equals(node, key))
136+
return value;
137+
}
138+
139+
return base.Visit(node);
86140
}
87141
}
88142
}

0 commit comments

Comments
 (0)