55using System . Linq . Expressions ;
66using System . Reflection ;
77using NHibernate . Linq . Visitors ;
8+ using NHibernate . Util ;
89
910namespace NHibernate . Linq
1011{
1112 public abstract class Assignments
1213 {
1314 protected static readonly ConstructorInfo DictionaryConstructorInfo = typeof ( Dictionary < string , object > ) . GetConstructor ( new [ ] { typeof ( int ) } ) ;
14- protected static readonly MethodInfo DictionaryAddMethodInfo = typeof ( Dictionary < string , object > ) . GetMethod ( " Add" ) ;
15+ protected static readonly MethodInfo DictionaryAddMethodInfo = ReflectHelper . GetMethod < Dictionary < string , object > > ( d => d . Add ( null , null ) ) ;
1516 }
1617
1718 /// <summary>
18- /// Class to hold assignments used in updates and inserts
19+ /// Class to hold assignments used in updates and inserts.
1920 /// </summary>
20- /// <typeparam name="TInput ">The type of the input .</typeparam>
21- /// <typeparam name="TOutput ">The type of the output .</typeparam>
22- public class Assignments < TInput , TOutput > : Assignments
21+ /// <typeparam name="TSource ">The type of the entity source of the insert or to update .</typeparam>
22+ /// <typeparam name="TTarget ">The type of the entity to insert or to update .</typeparam>
23+ public class Assignments < TSource , TTarget > : Assignments
2324 {
2425 private readonly List < Assignment > _sets = new List < Assignment > ( ) ;
2526
@@ -29,16 +30,12 @@ public class Assignments<TInput, TOutput> : Assignments
2930 /// <typeparam name="TProp">The type of the property.</typeparam>
3031 /// <param name="property">The property.</param>
3132 /// <param name="expression">The expression that should be assigned to the property.</param>
32- /// <returns></returns>
33- public Assignments < TInput , TOutput > Set < TProp > ( Expression < Func < TOutput , TProp > > property , Expression < Func < TInput , TProp > > expression )
33+ /// <returns>The current assignments list. </returns>
34+ public Assignments < TSource , TTarget > Set < TProp > ( Expression < Func < TTarget , TProp > > property , Expression < Func < TSource , TProp > > expression )
3435 {
35- if ( property == null )
36- throw new ArgumentNullException ( nameof ( property ) ) ;
3736 if ( expression == null )
3837 throw new ArgumentNullException ( nameof ( expression ) ) ;
39- var param = property . Parameters . Single ( ) ;
40- var member = property . Body as MemberExpression ??
41- throw new ArgumentException ( "The property expression must refer to a property of " + param . Name + "(" + param . Type . Name + ")" , nameof ( property ) ) ;
38+ var member = GetMemberExpression ( property ) ;
4239 _sets . Add ( new Assignment ( member . GetMemberPath ( ) , expression ) ) ;
4340 return this ;
4441 }
@@ -49,25 +46,31 @@ public Assignments<TInput, TOutput> Set<TProp>(Expression<Func<TOutput, TProp>>
4946 /// <typeparam name="TProp">The type of the property.</typeparam>
5047 /// <param name="property">The property.</param>
5148 /// <param name="value">The value.</param>
52- /// <returns></returns>
53- public Assignments < TInput , TOutput > Set < TProp > ( Expression < Func < TOutput , TProp > > property , TProp value )
49+ /// <returns>The current assignments list.</returns>
50+ public Assignments < TSource , TTarget > Set < TProp > ( Expression < Func < TTarget , TProp > > property , TProp value )
51+ {
52+ var member = GetMemberExpression ( property ) ;
53+ _sets . Add ( new Assignment ( member . GetMemberPath ( ) , Expression . Constant ( value , typeof ( TProp ) ) ) ) ;
54+ return this ;
55+ }
56+
57+ private static MemberExpression GetMemberExpression < TProp > ( Expression < Func < TTarget , TProp > > property )
5458 {
5559 if ( property == null )
5660 throw new ArgumentNullException ( nameof ( property ) ) ;
5761 var param = property . Parameters . Single ( ) ;
5862 var member = property . Body as MemberExpression ??
59- throw new ArgumentException ( "The property expression must refer to a property of " + param . Name + "(" + param . Type . Name + ")" , nameof ( property ) ) ;
60- _sets . Add ( new Assignment ( member . GetMemberPath ( ) , Expression . Constant ( value , typeof ( TProp ) ) ) ) ;
61- return this ;
63+ throw new ArgumentException ( $ "The property expression must refer to a property of { param . Name } ({ param . Type . Name } )", nameof ( property ) ) ;
64+ return member ;
6265 }
6366
6467 /// <summary>
65- /// Converts the assignments into a to lambda expression, which creates a Dictionary<string,object%gt;.
68+ /// Converts the assignments into a lambda expression, which creates a Dictionary<string,object%gt;.
6669 /// </summary>
67- /// <returns></returns>
70+ /// <returns>A lambda expression representing the assignments. </returns>
6871 public LambdaExpression ConvertToDictionaryExpression ( )
6972 {
70- var param = Expression . Parameter ( typeof ( TInput ) ) ;
73+ var param = Expression . Parameter ( typeof ( TSource ) ) ;
7174 var inits = new List < ElementInit > ( ) ;
7275 foreach ( var set in _sets )
7376 {
@@ -77,44 +80,43 @@ public LambdaExpression ConvertToDictionaryExpression()
7780 setter = setterLambda . Body . Replace ( setterLambda . Parameters . First ( ) , param ) ;
7881 }
7982 inits . Add ( Expression . ElementInit ( DictionaryAddMethodInfo , Expression . Constant ( set . PropertyPath ) ,
80- Expression . Convert (
81- setter ,
82- typeof ( object ) ) ) ) ;
83-
83+ Expression . Convert ( setter , typeof ( object ) ) ) ) ;
8484 }
8585
86-
8786 //The ListInit is intentionally "infected" with the lambda parameter (param), in the form of an IIF.
8887 //The only relevance is to make sure that the ListInit is not evaluated by the PartialEvaluatingExpressionTreeVisitor,
89- //which could turn it into a Constant
88+ //which could turn it into a Constant
9089 var listInit = Expression . ListInit (
9190 Expression . New (
9291 DictionaryConstructorInfo ,
9392 Expression . Condition (
94- Expression . Equal ( param , Expression . Constant ( null , typeof ( TInput ) ) ) ,
93+ Expression . Equal ( param , Expression . Constant ( null , typeof ( TSource ) ) ) ,
9594 Expression . Constant ( _sets . Count ) ,
9695 Expression . Constant ( _sets . Count ) ) ) ,
9796 inits ) ;
9897
99-
100-
10198 return Expression . Lambda ( listInit , param ) ;
10299 }
103100
104- public static Assignments < TInput , TOutput > FromExpression ( Expression < Func < TInput , TOutput > > expression )
101+ /// <summary>
102+ /// Converts a members initialization expression to assignments. Unset members are ignored and left untouched.
103+ /// </summary>
104+ /// <param name="expression">The expression to convert.</param>
105+ /// <returns>The corresponding assignments.</returns>
106+ public static Assignments < TSource , TTarget > FromExpression ( Expression < Func < TSource , TTarget > > expression )
105107 {
106108 if ( expression == null )
107109 throw new ArgumentNullException ( nameof ( expression ) ) ;
108- var instance = new Assignments < TInput , TOutput > ( ) ;
110+ var instance = new Assignments < TSource , TTarget > ( ) ;
109111 var memberInitExpression = expression . Body as MemberInitExpression ??
110- throw new ArgumentException ( "The expression must be member initialization, e.g. x => new Dog{ Name = x.Name,Age = x.Age + 5}" ) ;
111-
112+ throw new ArgumentException ( "The expression must be member initialization, e.g. x => new Dog { Name = x.Name, Age = x.Age + 5 }" ) ;
113+
112114 AddSetsFromBindings ( memberInitExpression . Bindings , instance , "" , expression . Parameters ) ;
113-
115+
114116 return instance ;
115117 }
116118
117- private static void AddSetsFromBindings ( IEnumerable < MemberBinding > bindings , Assignments < TInput , TOutput > instance , string path , ReadOnlyCollection < ParameterExpression > parameters )
119+ private static void AddSetsFromBindings ( IEnumerable < MemberBinding > bindings , Assignments < TSource , TTarget > instance , string path , ReadOnlyCollection < ParameterExpression > parameters )
118120 {
119121 foreach ( var binding in bindings )
120122 {
@@ -124,12 +126,12 @@ private static void AddSetsFromBindings(IEnumerable<MemberBinding> bindings, Ass
124126 }
125127 else if ( binding . BindingType == MemberBindingType . MemberBinding ) // {Property={SubProperty="Value}}
126128 {
127- AddSetsFromBindings ( ( ( MemberMemberBinding ) binding ) . Bindings , instance , path + "." + binding . Member . Name , parameters ) ;
129+ AddSetsFromBindings ( ( ( MemberMemberBinding ) binding ) . Bindings , instance , path + "." + binding . Member . Name , parameters ) ;
128130 }
129131 }
130132 }
131133
132- private static void AddSetsFromAssignment ( MemberAssignment assignment , Assignments < TInput , TOutput > instance , string path , ReadOnlyCollection < ParameterExpression > parameters )
134+ private static void AddSetsFromAssignment ( MemberAssignment assignment , Assignments < TSource , TTarget > instance , string path , ReadOnlyCollection < ParameterExpression > parameters )
133135 {
134136 // {Property=new Instance{SubProperty="Value"}}
135137 if ( assignment . Expression is MemberInitExpression memberInit )
0 commit comments