1414using System . Linq . Expressions ;
1515using System . Text . RegularExpressions ;
1616using NHibernate . DomainModel . Northwind . Entities ;
17- using NUnit . Framework ;
1817using NHibernate . Linq ;
18+ using NUnit . Framework ;
1919
2020namespace NHibernate . Test . Linq
2121{
@@ -30,7 +30,8 @@ public async Task UsingArrayParameterTwiceAsync()
3030 var ids = new [ ] { 11008 , 11019 , 11039 } ;
3131 await ( AssertTotalParametersAsync (
3232 db . Orders . Where ( o => ids . Contains ( o . OrderId ) && ids . Contains ( o . OrderId ) ) ,
33- ids . Length ) ) ;
33+ ids . Length ,
34+ 1 ) ) ;
3435 }
3536
3637 [ Test ]
@@ -40,7 +41,8 @@ public async Task UsingTwoArrayParametersAsync()
4041 var ids2 = new [ ] { 11008 , 11019 , 11039 } ;
4142 await ( AssertTotalParametersAsync (
4243 db . Orders . Where ( o => ids . Contains ( o . OrderId ) && ids2 . Contains ( o . OrderId ) ) ,
43- ids . Length + ids2 . Length ) ) ;
44+ ids . Length + ids2 . Length ,
45+ 2 ) ) ;
4446 }
4547
4648 [ Test ]
@@ -49,7 +51,8 @@ public async Task UsingListParameterTwiceAsync()
4951 var ids = new List < int > { 11008 , 11019 , 11039 } ;
5052 await ( AssertTotalParametersAsync (
5153 db . Orders . Where ( o => ids . Contains ( o . OrderId ) && ids . Contains ( o . OrderId ) ) ,
52- ids . Count ) ) ;
54+ ids . Count ,
55+ 1 ) ) ;
5356 }
5457
5558 [ Test ]
@@ -59,7 +62,8 @@ public async Task UsingTwoListParametersAsync()
5962 var ids2 = new List < int > { 11008 , 11019 , 11039 } ;
6063 await ( AssertTotalParametersAsync (
6164 db . Orders . Where ( o => ids . Contains ( o . OrderId ) && ids2 . Contains ( o . OrderId ) ) ,
62- ids . Count + ids2 . Count ) ) ;
65+ ids . Count + ids2 . Count ,
66+ 2 ) ) ;
6367 }
6468
6569 [ Test ]
@@ -108,6 +112,16 @@ public async Task UsingNegateValueTypeParameterAsync()
108112 2 ) ) ;
109113 }
110114
115+ [ Test ]
116+ public async Task UsingValueTypeParameterInArrayAsync ( )
117+ {
118+ var id = 11008 ;
119+ await ( AssertTotalParametersAsync (
120+ db . Orders . Where ( o => new [ ] { id , 11019 } . Contains ( o . OrderId ) && new [ ] { id , 11019 } . Contains ( o . OrderId ) ) ,
121+ 4 ,
122+ 2 ) ) ;
123+ }
124+
111125 [ Test ]
112126 public async Task UsingTwoValueTypeParametersAsync ( )
113127 {
@@ -156,6 +170,22 @@ public async Task UsingTwoObjectPropertyParametersAsync()
156170 2 ) ) ;
157171 }
158172
173+ [ Test ]
174+ public async Task UsingParameterInWhereSkipTakeAsync ( )
175+ {
176+ var value3 = 1 ;
177+ var q1 = db . Products . Where ( o => o . ProductId < value3 ) . Take ( value3 ) . Skip ( value3 ) ;
178+ await ( AssertTotalParametersAsync ( q1 , 3 ) ) ;
179+ }
180+
181+ [ Test ]
182+ public async Task UsingParameterInTwoWhereAsync ( )
183+ {
184+ var value3 = 1 ;
185+ var q1 = db . Products . Where ( o => o . ProductId < value3 ) . Where ( o => o . ProductId < value3 ) ;
186+ await ( AssertTotalParametersAsync ( q1 , 1 ) ) ;
187+ }
188+
159189 [ Test ]
160190 public async Task UsingObjectNestedPropertyParameterTwiceAsync ( )
161191 {
@@ -213,18 +243,142 @@ public async Task UsingObjectPropertyParameterWithThirdLevelClosureAsync()
213243 1 ) ) ;
214244 }
215245
216- private static async Task AssertTotalParametersAsync < T > ( IQueryable < T > query , int parameterNumber , CancellationToken cancellationToken = default ( CancellationToken ) )
246+ [ Test ]
247+ public async Task UsingParameterInDMLInsertIntoFourTimesAsync ( )
248+ {
249+ var value = "test" ;
250+ await ( AssertTotalParametersAsync (
251+ QueryMode . Insert ,
252+ db . Customers . Where ( c => c . CustomerId == value ) ,
253+ x => new Customer { CustomerId = value , ContactName = value , CompanyName = value } ,
254+ 4 ) ) ;
255+ }
256+
257+ [ Test ]
258+ public async Task UsingFourParametersInDMLInsertIntoAsync ( )
259+ {
260+ var value = "test" ;
261+ var value2 = "test" ;
262+ var value3 = "test" ;
263+ var value4 = "test" ;
264+ await ( AssertTotalParametersAsync (
265+ QueryMode . Insert ,
266+ db . Customers . Where ( c => c . CustomerId == value3 ) ,
267+ x => new Customer { CustomerId = value4 , ContactName = value2 , CompanyName = value } ,
268+ 4 ) ) ;
269+ }
270+
271+ [ Test ]
272+ public async Task UsingParameterInDMLUpdateThreeTimesAsync ( )
273+ {
274+ var value = "test" ;
275+ await ( AssertTotalParametersAsync (
276+ QueryMode . Update ,
277+ db . Customers . Where ( c => c . CustomerId == value ) ,
278+ x => new Customer { ContactName = value , CompanyName = value } ,
279+ 3 ) ) ;
280+ }
281+
282+ [ Test ]
283+ public async Task UsingThreeParametersInDMLUpdateAsync ( )
284+ {
285+ var value = "test" ;
286+ var value2 = "test" ;
287+ var value3 = "test" ;
288+ await ( AssertTotalParametersAsync (
289+ QueryMode . Update ,
290+ db . Customers . Where ( c => c . CustomerId == value3 ) ,
291+ x => new Customer { ContactName = value2 , CompanyName = value } ,
292+ 3 ) ) ;
293+ }
294+
295+ [ Test ]
296+ public async Task UsingParameterInDMLDeleteTwiceAsync ( )
297+ {
298+ var value = "test" ;
299+ await ( AssertTotalParametersAsync (
300+ QueryMode . Delete ,
301+ db . Customers . Where ( c => c . CustomerId == value && c . CompanyName == value ) ,
302+ 2 ) ) ;
303+ }
304+
305+ [ Test ]
306+ public async Task UsingTwoParametersInDMLDeleteAsync ( )
307+ {
308+ var value = "test" ;
309+ var value2 = "test" ;
310+ await ( AssertTotalParametersAsync (
311+ QueryMode . Delete ,
312+ db . Customers . Where ( c => c . CustomerId == value && c . CompanyName == value2 ) ,
313+ 2 ) ) ;
314+ }
315+
316+ private async Task AssertTotalParametersAsync < T > ( IQueryable < T > query , int parameterNumber , int ? linqParameterNumber = null , CancellationToken cancellationToken = default ( CancellationToken ) )
217317 {
218318 using ( var sqlSpy = new SqlLogSpy ( ) )
219319 {
320+ // In case of arrays linqParameterNumber and parameterNumber will be different
321+ Assert . That (
322+ GetLinqExpression ( query ) . ParameterValuesByName . Count ,
323+ Is . EqualTo ( linqParameterNumber ?? parameterNumber ) ,
324+ "Linq expression has different number of parameters" ) ;
325+
220326 await ( query . ToListAsync ( cancellationToken ) ) ;
221- var sqlParameters = sqlSpy . GetWholeLog ( ) . Split ( ';' ) [ 1 ] ;
222- var matches = Regex . Matches ( sqlParameters , @"([\d\w]+)[\s]+\=" , RegexOptions . IgnoreCase ) ;
327+ AssertParameters ( sqlSpy , parameterNumber ) ;
328+ }
329+ }
330+
331+ private static Task AssertTotalParametersAsync < T > ( QueryMode queryMode , IQueryable < T > query , int parameterNumber , CancellationToken cancellationToken = default ( CancellationToken ) )
332+ {
333+ return AssertTotalParametersAsync ( queryMode , query , null , parameterNumber , cancellationToken ) ;
334+ }
335+
336+ private static async Task AssertTotalParametersAsync < T > ( QueryMode queryMode , IQueryable < T > query , Expression < Func < T , T > > expression , int parameterNumber , CancellationToken cancellationToken = default ( CancellationToken ) )
337+ {
338+ var provider = query . Provider as INhQueryProvider ;
339+ Assert . That ( provider , Is . Not . Null ) ;
223340
224- // Due to ODBC drivers not supporting parameter names, we have to do a distinct of parameter names.
225- var distinctParameters = matches . OfType < Match > ( ) . Select ( m => m . Groups [ 1 ] . Value . Trim ( ) ) . Distinct ( ) . ToList ( ) ;
226- Assert . That ( distinctParameters , Has . Count . EqualTo ( parameterNumber ) ) ;
341+ var dmlExpression = expression != null
342+ ? DmlExpressionRewriter . PrepareExpression ( query . Expression , expression )
343+ : query . Expression ;
344+
345+ using ( var sqlSpy = new SqlLogSpy ( ) )
346+ {
347+ Assert . That ( await ( provider . ExecuteDmlAsync < T > ( queryMode , dmlExpression , cancellationToken ) ) , Is . EqualTo ( 0 ) , "The DML query updated the data" ) ; // Avoid updating the data
348+ AssertParameters ( sqlSpy , parameterNumber ) ;
227349 }
228350 }
351+
352+ private static void AssertParameters ( SqlLogSpy sqlSpy , int parameterNumber )
353+ {
354+ var sqlParameters = sqlSpy . GetWholeLog ( ) . Split ( ';' ) [ 1 ] ;
355+ var matches = Regex . Matches ( sqlParameters , @"([\d\w]+)[\s]+\=" , RegexOptions . IgnoreCase ) ;
356+
357+ // Due to ODBC drivers not supporting parameter names, we have to do a distinct of parameter names.
358+ var distinctParameters = matches . OfType < Match > ( ) . Select ( m => m . Groups [ 1 ] . Value . Trim ( ) ) . Distinct ( ) . ToList ( ) ;
359+ Assert . That ( distinctParameters , Has . Count . EqualTo ( parameterNumber ) ) ;
360+ }
361+
362+ private NhLinqExpression GetLinqExpression < T > ( QueryMode queryMode , IQueryable < T > query , Expression < Func < T , T > > expression )
363+ {
364+ return GetLinqExpression ( queryMode , DmlExpressionRewriter . PrepareExpression ( query . Expression , expression ) ) ;
365+ }
366+
367+ private NhLinqExpression GetLinqExpression < T > ( QueryMode queryMode , IQueryable < T > query )
368+ {
369+ return GetLinqExpression ( queryMode , query . Expression ) ;
370+ }
371+
372+ private NhLinqExpression GetLinqExpression < T > ( IQueryable < T > query )
373+ {
374+ return GetLinqExpression ( QueryMode . Select , query . Expression ) ;
375+ }
376+
377+ private NhLinqExpression GetLinqExpression ( QueryMode queryMode , Expression expression )
378+ {
379+ return queryMode == QueryMode . Select
380+ ? new NhLinqExpression ( expression , Sfi )
381+ : new NhLinqDmlExpression < Customer > ( queryMode , expression , Sfi ) ;
382+ }
229383 }
230384}
0 commit comments