1
1
using System ;
2
2
using System . Collections . Generic ;
3
- using System . Collections . ObjectModel ;
4
3
using System . Linq ;
5
4
using System . Linq . Expressions ;
6
- using System . Reflection ;
7
5
using NHibernate . Linq . Visitors ;
8
- using NHibernate . Util ;
9
6
10
7
namespace NHibernate . Linq
11
8
{
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
-
18
9
/// <summary>
19
10
/// Class to hold assignments used in updates and inserts.
20
11
/// </summary>
21
12
/// <typeparam name="TSource">The type of the entity source of the insert or to update.</typeparam>
22
13
/// <typeparam name="TTarget">The type of the entity to insert or to update.</typeparam>
23
- public class Assignments < TSource , TTarget > : Assignments
14
+ public class Assignments < TSource , TTarget >
24
15
{
25
- private readonly List < Assignment > _sets = new List < Assignment > ( ) ;
16
+ private readonly Dictionary < string , Expression > _assignments = new Dictionary < string , Expression > ( ) ;
17
+
18
+ internal IReadOnlyDictionary < string , Expression > List => _assignments ;
26
19
27
20
/// <summary>
28
21
/// Sets the specified property.
@@ -36,7 +29,7 @@ public Assignments<TSource, TTarget> Set<TProp>(Expression<Func<TTarget, TProp>>
36
29
if ( expression == null )
37
30
throw new ArgumentNullException ( nameof ( expression ) ) ;
38
31
var member = GetMemberExpression ( property ) ;
39
- _sets . Add ( new Assignment ( member . GetMemberPath ( ) , expression ) ) ;
32
+ _assignments . Add ( member . GetMemberPath ( ) , expression ) ;
40
33
return this ;
41
34
}
42
35
@@ -50,7 +43,7 @@ public Assignments<TSource, TTarget> Set<TProp>(Expression<Func<TTarget, TProp>>
50
43
public Assignments < TSource , TTarget > Set < TProp > ( Expression < Func < TTarget , TProp > > property , TProp value )
51
44
{
52
45
var member = GetMemberExpression ( property ) ;
53
- _sets . Add ( new Assignment ( member . GetMemberPath ( ) , Expression . Constant ( value , typeof ( TProp ) ) ) ) ;
46
+ _assignments . Add ( member . GetMemberPath ( ) , Expression . Constant ( value , typeof ( TProp ) ) ) ;
54
47
return this ;
55
48
}
56
49
@@ -63,85 +56,5 @@ private static MemberExpression GetMemberExpression<TProp>(Expression<Func<TTarg
63
56
throw new ArgumentException ( $ "The property expression must refer to a property of { param . Name } ({ param . Type . Name } )", nameof ( property ) ) ;
64
57
return member ;
65
58
}
66
-
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
-
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 )
107
- {
108
- if ( expression == null )
109
- throw new ArgumentNullException ( nameof ( expression ) ) ;
110
- var instance = new Assignments < TSource , TTarget > ( ) ;
111
- 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 ) ;
115
-
116
- return instance ;
117
- }
118
-
119
- private static void AddSetsFromBindings ( IEnumerable < MemberBinding > bindings , Assignments < TSource , TTarget > instance , string path , ReadOnlyCollection < ParameterExpression > parameters )
120
- {
121
- foreach ( var binding in bindings )
122
- {
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}}
128
- {
129
- AddSetsFromBindings ( ( ( MemberMemberBinding ) binding ) . Bindings , instance , path + "." + binding . Member . Name , parameters ) ;
130
- }
131
- }
132
- }
133
-
134
- private static void AddSetsFromAssignment ( MemberAssignment assignment , Assignments < TSource , TTarget > instance , string path , ReadOnlyCollection < ParameterExpression > parameters )
135
- {
136
- // {Property=new Instance{SubProperty="Value"}}
137
- if ( assignment . Expression is MemberInitExpression memberInit )
138
- {
139
- AddSetsFromBindings ( memberInit . Bindings , instance , path , parameters ) ;
140
- }
141
- else
142
- {
143
- instance . _sets . Add ( new Assignment ( path . Substring ( 1 ) , Expression . Lambda ( assignment . Expression , parameters ) ) ) ;
144
- }
145
- }
146
59
}
147
60
}
0 commit comments