66using System . Reflection ;
77using Mapster . EFCore ;
88using Microsoft . EntityFrameworkCore ;
9+ using Microsoft . EntityFrameworkCore . Query ;
910
1011namespace 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