5
5
using System . Linq . Expressions ;
6
6
using System . Reflection ;
7
7
using NHibernate . Linq . Visitors ;
8
+ using NHibernate . Util ;
8
9
9
10
namespace NHibernate . Linq
10
11
{
11
12
public abstract class Assignments
12
13
{
13
14
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 ) ) ;
15
16
}
16
17
17
18
/// <summary>
18
- /// Class to hold assignments used in updates and inserts
19
+ /// Class to hold assignments used in updates and inserts.
19
20
/// </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
23
24
{
24
25
private readonly List < Assignment > _sets = new List < Assignment > ( ) ;
25
26
@@ -29,16 +30,12 @@ public class Assignments<TInput, TOutput> : Assignments
29
30
/// <typeparam name="TProp">The type of the property.</typeparam>
30
31
/// <param name="property">The property.</param>
31
32
/// <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 )
34
35
{
35
- if ( property == null )
36
- throw new ArgumentNullException ( nameof ( property ) ) ;
37
36
if ( expression == null )
38
37
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 ) ;
42
39
_sets . Add ( new Assignment ( member . GetMemberPath ( ) , expression ) ) ;
43
40
return this ;
44
41
}
@@ -49,25 +46,31 @@ public Assignments<TInput, TOutput> Set<TProp>(Expression<Func<TOutput, TProp>>
49
46
/// <typeparam name="TProp">The type of the property.</typeparam>
50
47
/// <param name="property">The property.</param>
51
48
/// <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 )
54
58
{
55
59
if ( property == null )
56
60
throw new ArgumentNullException ( nameof ( property ) ) ;
57
61
var param = property . Parameters . Single ( ) ;
58
62
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 ;
62
65
}
63
66
64
67
/// <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;.
66
69
/// </summary>
67
- /// <returns></returns>
70
+ /// <returns>A lambda expression representing the assignments. </returns>
68
71
public LambdaExpression ConvertToDictionaryExpression ( )
69
72
{
70
- var param = Expression . Parameter ( typeof ( TInput ) ) ;
73
+ var param = Expression . Parameter ( typeof ( TSource ) ) ;
71
74
var inits = new List < ElementInit > ( ) ;
72
75
foreach ( var set in _sets )
73
76
{
@@ -77,44 +80,43 @@ public LambdaExpression ConvertToDictionaryExpression()
77
80
setter = setterLambda . Body . Replace ( setterLambda . Parameters . First ( ) , param ) ;
78
81
}
79
82
inits . Add ( Expression . ElementInit ( DictionaryAddMethodInfo , Expression . Constant ( set . PropertyPath ) ,
80
- Expression . Convert (
81
- setter ,
82
- typeof ( object ) ) ) ) ;
83
-
83
+ Expression . Convert ( setter , typeof ( object ) ) ) ) ;
84
84
}
85
85
86
-
87
86
//The ListInit is intentionally "infected" with the lambda parameter (param), in the form of an IIF.
88
87
//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
90
89
var listInit = Expression . ListInit (
91
90
Expression . New (
92
91
DictionaryConstructorInfo ,
93
92
Expression . Condition (
94
- Expression . Equal ( param , Expression . Constant ( null , typeof ( TInput ) ) ) ,
93
+ Expression . Equal ( param , Expression . Constant ( null , typeof ( TSource ) ) ) ,
95
94
Expression . Constant ( _sets . Count ) ,
96
95
Expression . Constant ( _sets . Count ) ) ) ,
97
96
inits ) ;
98
97
99
-
100
-
101
98
return Expression . Lambda ( listInit , param ) ;
102
99
}
103
100
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 )
105
107
{
106
108
if ( expression == null )
107
109
throw new ArgumentNullException ( nameof ( expression ) ) ;
108
- var instance = new Assignments < TInput , TOutput > ( ) ;
110
+ var instance = new Assignments < TSource , TTarget > ( ) ;
109
111
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
+
112
114
AddSetsFromBindings ( memberInitExpression . Bindings , instance , "" , expression . Parameters ) ;
113
-
115
+
114
116
return instance ;
115
117
}
116
118
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 )
118
120
{
119
121
foreach ( var binding in bindings )
120
122
{
@@ -124,12 +126,12 @@ private static void AddSetsFromBindings(IEnumerable<MemberBinding> bindings, Ass
124
126
}
125
127
else if ( binding . BindingType == MemberBindingType . MemberBinding ) // {Property={SubProperty="Value}}
126
128
{
127
- AddSetsFromBindings ( ( ( MemberMemberBinding ) binding ) . Bindings , instance , path + "." + binding . Member . Name , parameters ) ;
129
+ AddSetsFromBindings ( ( ( MemberMemberBinding ) binding ) . Bindings , instance , path + "." + binding . Member . Name , parameters ) ;
128
130
}
129
131
}
130
132
}
131
133
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 )
133
135
{
134
136
// {Property=new Instance{SubProperty="Value"}}
135
137
if ( assignment . Expression is MemberInitExpression memberInit )
0 commit comments