44using Microsoft . EntityFrameworkCore ;
55using MySql . EntityFrameworkCore . Extensions ;
66using System ;
7+ using System . Linq ;
78using System . Threading . Tasks ;
89using Xunit ;
910
@@ -43,6 +44,20 @@ public virtual async Task UniqueColumnViolationThrowsUniqueConstraintException()
4344 }
4445 }
4546
47+ [ Fact ]
48+ public virtual async Task UniqueColumnViolationThrowsUniqueConstraintExceptionThroughExecuteUpdate ( )
49+ {
50+ DemoContext . Products . Add ( new Product { Name = "Bulk Update 1" } ) ;
51+ DemoContext . Products . Add ( new Product { Name = "Bulk Update 2" } ) ;
52+
53+ await DemoContext . SaveChangesAsync ( ) ;
54+ Assert . Throws < UniqueConstraintException > ( ( ) => DemoContext . Products . ExecuteUpdate ( p => p . SetProperty ( pp => pp . Name , "Bulk Update 1" ) ) ) ;
55+ await Assert . ThrowsAsync < UniqueConstraintException > ( async ( ) => await DemoContext . Products . ExecuteUpdateAsync ( p => p . SetProperty ( pp => pp . Name , "Bulk Update 1" ) ) ) ;
56+ await DemoContext . Products
57+ . Where ( p => p . Name == "Bulk Update 1" || p . Name == "Bulk Update 2" )
58+ . ExecuteDeleteAsync ( ) ;
59+ }
60+
4661 [ Fact ]
4762 public virtual async Task UniqueColumnViolationSameNamesIndexesInDifferentSchemasSetsCorrectTableName ( )
4863 {
@@ -107,6 +122,17 @@ public virtual async Task RequiredColumnViolationThrowsCannotInsertNullException
107122 await Assert . ThrowsAsync < CannotInsertNullException > ( ( ) => DemoContext . SaveChangesAsync ( ) ) ;
108123 }
109124
125+ [ Fact ]
126+ public virtual async Task RequiredColumnViolationThrowsCannotInsertNullExceptionThroughExecuteUpdate ( )
127+ {
128+ DemoContext . Products . Add ( new Product { Name = "Bulk Update 1" } ) ;
129+ await DemoContext . SaveChangesAsync ( ) ;
130+
131+ Assert . Throws < CannotInsertNullException > ( ( ) => DemoContext . Products . ExecuteUpdate ( p => p . SetProperty ( pp => pp . Name , ( string ) null ) ) ) ;
132+ await Assert . ThrowsAsync < CannotInsertNullException > ( async ( ) => await DemoContext . Products . ExecuteUpdateAsync ( p => p . SetProperty ( pp => pp . Name , ( string ) null ) ) ) ;
133+ await DemoContext . Products . Where ( p => p . Name == "Bulk Update 1" ) . ExecuteDeleteAsync ( ) ;
134+ }
135+
110136 [ Fact ]
111137 public virtual async Task MaxLengthViolationThrowsMaxLengthExceededException ( )
112138 {
@@ -116,6 +142,38 @@ public virtual async Task MaxLengthViolationThrowsMaxLengthExceededException()
116142 await Assert . ThrowsAsync < MaxLengthExceededException > ( ( ) => DemoContext . SaveChangesAsync ( ) ) ;
117143 }
118144
145+ [ Fact ]
146+ public virtual async Task MaxLengthViolationThrowsMaxLengthExceededExceptionThroughExecuteUpdate ( )
147+ {
148+ DemoContext . Products . Add ( new Product { Name = "Bulk Update 1" } ) ;
149+ await DemoContext . SaveChangesAsync ( ) ;
150+
151+ CleanupContext ( ) ;
152+
153+ Assert . Throws < MaxLengthExceededException > ( Query ) ;
154+ await Assert . ThrowsAsync < MaxLengthExceededException > ( QueryAsync ) ;
155+
156+ await DemoContext . Products
157+ . Where ( p => p . Name == "Bulk Update 1" )
158+ . ExecuteDeleteAsync ( ) ;
159+
160+ return ;
161+
162+ void Query ( )
163+ {
164+ DemoContext . Products
165+ . Where ( p => p . Name == "Bulk Update 1" )
166+ . ExecuteUpdate ( p => p . SetProperty ( pp => pp . Name , new string ( 'G' , DemoContext . ProductNameMaxLength + 5 ) ) ) ;
167+ }
168+
169+ async Task QueryAsync ( )
170+ {
171+ await DemoContext . Products
172+ . Where ( p => p . Name == "Bulk Update 1" )
173+ . ExecuteUpdateAsync ( p => p . SetProperty ( pp => pp . Name , new string ( 'G' , DemoContext . ProductNameMaxLength + 5 ) ) ) ;
174+ }
175+ }
176+
119177 [ Fact ]
120178 public virtual async Task NumericOverflowViolationThrowsNumericOverflowException ( )
121179 {
@@ -127,6 +185,39 @@ public virtual async Task NumericOverflowViolationThrowsNumericOverflowException
127185 await Assert . ThrowsAsync < NumericOverflowException > ( ( ) => DemoContext . SaveChangesAsync ( ) ) ;
128186 }
129187
188+ [ Fact ]
189+ public virtual async Task NumericOverflowViolationThrowsNumericOverflowExceptionThroughExecuteUpdate ( )
190+ {
191+ var product = new Product { Name = "Numeric Overflow Test 2" } ;
192+ DemoContext . Products . Add ( product ) ;
193+ var sale = new ProductSale { Price = 1m , Product = product } ;
194+ DemoContext . ProductSales . Add ( sale ) ;
195+ await DemoContext . SaveChangesAsync ( ) ;
196+
197+ Assert . Throws < NumericOverflowException > ( Query ) ;
198+ await Assert . ThrowsAsync < NumericOverflowException > ( QueryAsync ) ;
199+
200+ DemoContext . Remove ( sale ) ;
201+ DemoContext . Remove ( product ) ;
202+ await DemoContext . SaveChangesAsync ( ) ;
203+
204+ return ;
205+
206+ void Query ( )
207+ {
208+ DemoContext . ProductSales
209+ . Where ( s => s . Id == sale . Id )
210+ . ExecuteUpdate ( s => s . SetProperty ( ss => ss . Price , 3141.59265m ) ) ;
211+ }
212+
213+ async Task QueryAsync ( )
214+ {
215+ await DemoContext . ProductSales
216+ . Where ( s => s . Id == sale . Id )
217+ . ExecuteUpdateAsync ( s => s . SetProperty ( ss => ss . Price , 3141.59265m ) ) ;
218+ }
219+ }
220+
130221 [ Fact ]
131222 public virtual async Task ReferenceViolationThrowsReferenceConstraintException ( )
132223 {
@@ -143,6 +234,46 @@ public virtual async Task ReferenceViolationThrowsReferenceConstraintException()
143234 }
144235 }
145236
237+ [ Fact ]
238+ public virtual async Task ReferenceViolationThrowsReferenceConstraintExceptionThroughExecuteUpdate ( )
239+ {
240+ var product = new Product { Name = "RefConstraint Violation 1" } ;
241+ DemoContext . Products . Add ( product ) ;
242+ var sale = new ProductSale { Price = 1m , Product = product } ;
243+ DemoContext . ProductSales . Add ( sale ) ;
244+ await DemoContext . SaveChangesAsync ( ) ;
245+
246+ var exception = Assert . Throws < ReferenceConstraintException > ( Query ) ;
247+ var asyncException = await Assert . ThrowsAsync < ReferenceConstraintException > ( QueryAsync ) ;
248+
249+ if ( ! isSqlite )
250+ {
251+ Assert . False ( string . IsNullOrEmpty ( exception . ConstraintName ) ) ;
252+ Assert . NotEmpty ( exception . ConstraintProperties ) ;
253+ Assert . Contains < string > ( nameof ( ProductSale . ProductId ) , exception . ConstraintProperties ) ;
254+
255+ Assert . False ( string . IsNullOrEmpty ( asyncException . ConstraintName ) ) ;
256+ Assert . NotEmpty ( asyncException . ConstraintProperties ) ;
257+ Assert . Contains < string > ( nameof ( ProductSale . ProductId ) , asyncException . ConstraintProperties ) ;
258+ }
259+
260+ return ;
261+
262+ void Query ( )
263+ {
264+ DemoContext . ProductSales
265+ . Where ( s => s . Id == sale . Id )
266+ . ExecuteUpdate ( s => s . SetProperty ( ss => ss . ProductId , 0 ) ) ;
267+ }
268+
269+ async Task QueryAsync ( )
270+ {
271+ await DemoContext . ProductSales
272+ . Where ( s => s . Id == sale . Id )
273+ . ExecuteUpdateAsync ( s => s . SetProperty ( ss => ss . ProductId , 0 ) ) ;
274+ }
275+ }
276+
146277 [ Fact ]
147278 public virtual async Task DatabaseUnrelatedExceptionThrowsOriginalException ( )
148279 {
@@ -176,6 +307,36 @@ public virtual async Task DeleteParentItemThrowsReferenceConstraintException()
176307 await Assert . ThrowsAsync < ReferenceConstraintException > ( ( ) => DemoContext . SaveChangesAsync ( ) ) ;
177308 }
178309
310+ [ Fact ]
311+ public virtual async Task DeleteParentItemThrowsReferenceConstraintExceptionThroughExecuteDelete ( )
312+ {
313+ var product = new Product { Name = "AN2" } ;
314+ var productPriceHistory = new ProductPriceHistory { Product = product , Price = 15.27m , EffectiveDate = DateTimeOffset . UtcNow } ;
315+ DemoContext . ProductPriceHistories . Add ( productPriceHistory ) ;
316+ await DemoContext . SaveChangesAsync ( ) ;
317+
318+ CleanupContext ( ) ;
319+
320+ Assert . Throws < ReferenceConstraintException > ( Query ) ;
321+ await Assert . ThrowsAsync < ReferenceConstraintException > ( QueryAsync ) ;
322+
323+ return ;
324+
325+ void Query ( )
326+ {
327+ DemoContext . Products
328+ . Where ( p => p . Name == "AN2" )
329+ . ExecuteDelete ( ) ;
330+ }
331+
332+ async Task QueryAsync ( )
333+ {
334+ await DemoContext . Products
335+ . Where ( p => p . Name == "AN2" )
336+ . ExecuteDeleteAsync ( ) ;
337+ }
338+ }
339+
179340 [ Fact ]
180341 public async Task NotHandledViolationReThrowsOriginalException ( )
181342 {
0 commit comments