33using System . Collections . ObjectModel ;
44using System . Linq ;
55using System . Linq . Expressions ;
6- using System . Reflection ;
76using NHibernate . Linq . Visitors ;
8- using NHibernate . Util ;
97
108namespace NHibernate . Linq
119{
12- public abstract class Assignments
13- {
14- protected static readonly ConstructorInfo DictionaryConstructorInfo = typeof ( Dictionary < string , object > ) . GetConstructor ( new [ ] { typeof ( int ) } ) ;
15- protected static readonly MethodInfo DictionaryAddMethodInfo = ReflectHelper . GetMethod < Dictionary < string , object > > ( d => d . Add ( null , null ) ) ;
16- }
17-
1810 /// <summary>
1911 /// Class to hold assignments used in updates and inserts.
2012 /// </summary>
2113 /// <typeparam name="TSource">The type of the entity source of the insert or to update.</typeparam>
2214 /// <typeparam name="TTarget">The type of the entity to insert or to update.</typeparam>
23- public class Assignments < TSource , TTarget > : Assignments
15+ public class Assignments < TSource , TTarget >
2416 {
2517 private readonly List < Assignment > _sets = new List < Assignment > ( ) ;
2618
19+ internal IReadOnlyCollection < Assignment > List => _sets ;
20+
2721 /// <summary>
2822 /// Sets the specified property.
2923 /// </summary>
@@ -64,40 +58,6 @@ private static MemberExpression GetMemberExpression<TProp>(Expression<Func<TTarg
6458 return member ;
6559 }
6660
67- /// <summary>
68- /// Converts the assignments into a lambda expression, which creates a Dictionary<string,object%gt;.
69- /// </summary>
70- /// <returns>A lambda expression representing the assignments.</returns>
71- public LambdaExpression ConvertToDictionaryExpression ( )
72- {
73- var param = Expression . Parameter ( typeof ( TSource ) ) ;
74- var inits = new List < ElementInit > ( ) ;
75- foreach ( var set in _sets )
76- {
77- var setter = set . Expression ;
78- if ( setter is LambdaExpression setterLambda )
79- {
80- setter = setterLambda . Body . Replace ( setterLambda . Parameters . First ( ) , param ) ;
81- }
82- inits . Add ( Expression . ElementInit ( DictionaryAddMethodInfo , Expression . Constant ( set . PropertyPath ) ,
83- Expression . Convert ( setter , typeof ( object ) ) ) ) ;
84- }
85-
86- //The ListInit is intentionally "infected" with the lambda parameter (param), in the form of an IIF.
87- //The only relevance is to make sure that the ListInit is not evaluated by the PartialEvaluatingExpressionTreeVisitor,
88- //which could turn it into a Constant
89- var listInit = Expression . ListInit (
90- Expression . New (
91- DictionaryConstructorInfo ,
92- Expression . Condition (
93- Expression . Equal ( param , Expression . Constant ( null , typeof ( TSource ) ) ) ,
94- Expression . Constant ( _sets . Count ) ,
95- Expression . Constant ( _sets . Count ) ) ) ,
96- inits ) ;
97-
98- return Expression . Lambda ( listInit , param ) ;
99- }
100-
10161 /// <summary>
10262 /// Converts a members initialization expression to assignments. Unset members are ignored and left untouched.
10363 /// </summary>
@@ -107,40 +67,42 @@ public static Assignments<TSource, TTarget> FromExpression(Expression<Func<TSour
10767 {
10868 if ( expression == null )
10969 throw new ArgumentNullException ( nameof ( expression ) ) ;
110- var instance = new Assignments < TSource , TTarget > ( ) ;
11170 var memberInitExpression = expression . Body as MemberInitExpression ??
112- throw new ArgumentException ( "The expression must be member initialization, e.g. x => new Dog { Name = x.Name, Age = x.Age + 5 }" ) ;
113-
114- AddSetsFromBindings ( memberInitExpression . Bindings , instance , "" , expression . Parameters ) ;
71+ throw new ArgumentException ( "The expression must be member initialization, e.g. x => new Dog { Name = x.Name, Age = x.Age + 5 }" ) ;
11572
73+ var instance = new Assignments < TSource , TTarget > ( ) ;
74+ instance . AddSetsFromBindings ( memberInitExpression . Bindings , "" , expression . Parameters ) ;
11675 return instance ;
11776 }
11877
119- private static void AddSetsFromBindings ( IEnumerable < MemberBinding > bindings , Assignments < TSource , TTarget > instance , string path , ReadOnlyCollection < ParameterExpression > parameters )
78+ private void AddSetsFromBindings ( IEnumerable < MemberBinding > bindings , string path , ReadOnlyCollection < ParameterExpression > parameters )
12079 {
121- foreach ( var binding in bindings )
80+ foreach ( var node in bindings )
12281 {
123- if ( binding . BindingType == MemberBindingType . Assignment ) // {Property="Value"}
124- {
125- AddSetsFromAssignment ( ( MemberAssignment ) binding , instance , path + "." + binding . Member . Name , parameters ) ;
126- }
127- else if ( binding . BindingType == MemberBindingType . MemberBinding ) // {Property={SubProperty="Value}}
82+ switch ( node . BindingType )
12883 {
129- AddSetsFromBindings ( ( ( MemberMemberBinding ) binding ) . Bindings , instance , path + "." + binding . Member . Name , parameters ) ;
84+ case MemberBindingType . Assignment :
85+ AddSetsFromAssignment ( ( MemberAssignment ) node , path + "." + node . Member . Name , parameters ) ;
86+ break ;
87+ case MemberBindingType . MemberBinding :
88+ AddSetsFromBindings ( ( ( MemberMemberBinding ) node ) . Bindings , path + "." + node . Member . Name , parameters ) ;
89+ break ;
90+ default :
91+ throw new InvalidOperationException ( $ "{ node . BindingType } is not supported") ;
13092 }
13193 }
13294 }
13395
134- private static void AddSetsFromAssignment ( MemberAssignment assignment , Assignments < TSource , TTarget > instance , string path , ReadOnlyCollection < ParameterExpression > parameters )
96+ private void AddSetsFromAssignment ( MemberAssignment assignment , string path , ReadOnlyCollection < ParameterExpression > parameters )
13597 {
13698 // {Property=new Instance{SubProperty="Value"}}
13799 if ( assignment . Expression is MemberInitExpression memberInit )
138100 {
139- AddSetsFromBindings ( memberInit . Bindings , instance , path , parameters ) ;
101+ AddSetsFromBindings ( memberInit . Bindings , path , parameters ) ;
140102 }
141103 else
142104 {
143- instance . _sets . Add ( new Assignment ( path . Substring ( 1 ) , Expression . Lambda ( assignment . Expression , parameters ) ) ) ;
105+ _sets . Add ( new Assignment ( path . Substring ( 1 ) , Expression . Lambda ( assignment . Expression , parameters ) ) ) ;
144106 }
145107 }
146108 }
0 commit comments