1- using System . Collections ;
21using System . Data . Common ;
3- using System . Reflection ;
42
53using EntityFrameworkCore . ExecuteInsert . Abstractions ;
64using EntityFrameworkCore . ExecuteInsert . Dialect ;
@@ -15,25 +13,13 @@ namespace EntityFrameworkCore.ExecuteInsert;
1513public abstract class BulkInsertProviderBase < TDialect > : IBulkInsertProvider
1614 where TDialect : SqlDialectBuilder , new ( )
1715{
18- protected readonly TDialect SqlDialect ;
19-
20- protected BulkInsertProviderBase ( )
21- {
22- SqlDialect = new TDialect ( ) ;
23- }
16+ protected readonly TDialect SqlDialect = new ( ) ;
2417
2518 protected virtual string BulkInsertId => "_bulk_insert_id" ;
2619
27- private static readonly MethodInfo CastMethod = typeof ( Enumerable ) . GetMethod ( "Cast" ) ! ;
28- private static readonly MethodInfo BulkInsertPkMethod = typeof ( BulkInsertProviderBase < TDialect > ) . GetMethod ( nameof ( BulkInsertWithPrimaryKeyAsync ) ) ! ;
29- private static readonly MethodInfo GetChildrenMethod = typeof ( BulkInsertProviderBase < TDialect > ) . GetMethod ( nameof ( GetChildrenEntities ) ) ! ;
30-
3120 protected abstract string CreateTableCopySql { get ; }
3221 protected abstract string AddTableCopyBulkInsertId { get ; }
3322
34- private static readonly MethodInfo GetFieldValueMethod =
35- typeof ( DbDataReader ) . GetMethod ( nameof ( DbDataReader . GetFieldValue ) ) ! ;
36-
3723 protected async Task < string > CreateTableCopyAsync < T > (
3824 DbContext context ,
3925 DbConnection connection ,
@@ -89,67 +75,6 @@ public async Task<List<T>> CopyFromTempTableAsync<T>(DbContext context,
8975 cancellationToken : cancellationToken ) ;
9076 }
9177
92- public async Task < List < KeyValuePair < long , object [ ] > > > CopyFromTempTablePrimaryKeyAsync < T > (
93- DbContext context ,
94- DbConnection connection ,
95- string tempTableName ,
96- BulkInsertOptions options ,
97- CancellationToken cancellationToken = default ) where T : class
98- {
99- return await CopyFromTempTableWithKeysAsync < T , object [ ] > (
100- context ,
101- connection ,
102- tempTableName ,
103- options ,
104- cancellationToken : cancellationToken
105- ) ;
106- }
107-
108- private async Task < List < KeyValuePair < long , TResult > > > CopyFromTempTableWithKeysAsync < T , TResult > (
109- DbContext context ,
110- DbConnection connection ,
111- string tempTableName ,
112- BulkInsertOptions options ,
113- CancellationToken cancellationToken = default
114- )
115- where T : class
116- where TResult : class
117- {
118- var ( schemaName , tableName , primaryKey ) = GetTableInfo ( context , typeof ( T ) ) ;
119- var escapedTableName = EscapeTableName ( schemaName , tableName ) ;
120-
121- var indexColumn = Escape ( BulkInsertId ) ;
122- var returnedColumns = new [ ] { indexColumn }
123- . Concat ( primaryKey . Properties . Select ( p => Escape ( p . GetColumnName ( ) ) ) ) . ToArray ( ) ;
124-
125- var query = "" ; //BuildInsertSelectQuery(tempTableName, escapedTableName, returnedColumns, returnedColumns, moveRows);
126-
127- var result = new List < KeyValuePair < long , TResult > > ( ) ;
128-
129- await using var command = connection . CreateCommand ( ) ;
130- command . CommandText = query ;
131-
132- var getFieldValueMethods = primaryKey . Properties
133- . Select ( p => GetFieldValueMethod . MakeGenericMethod ( p . ClrType ) )
134- . ToArray ( ) ;
135-
136- await using var reader = await command . ExecuteReaderAsync ( cancellationToken ) ;
137- while ( await reader . ReadAsync ( cancellationToken ) )
138- {
139- var index = ( long ) reader . GetValue ( 0 ) ;
140- var values = new object [ primaryKey . Properties . Count ] ;
141- for ( var i = 0 ; i < primaryKey . Properties . Count ; i ++ )
142- {
143- values [ i ] = getFieldValueMethods [ i ] . Invoke ( reader , new object [ ] { i + 1 } ) ! ;
144- }
145-
146- var entity = Activator . CreateInstance ( typeof ( TResult ) , values ) as TResult ;
147- result . Add ( new KeyValuePair < long , TResult > ( index , entity ! ) ) ;
148- }
149-
150- return result ;
151- }
152-
15378 private async Task < List < TResult > > CopyFromTempTableWithoutKeysAsync < T , TResult > ( DbContext context ,
15479 DbConnection connection ,
15580 string tempTableName ,
@@ -204,27 +129,6 @@ public async Task<List<T>> BulkInsertWithIdentityAsync<T>(
204129 return result ;
205130 }
206131
207- public async Task < List < KeyValuePair < long , object [ ] > > > BulkInsertWithPrimaryKeyAsync < T > (
208- DbContext context ,
209- IEnumerable < T > entities ,
210- BulkInsertOptions options ,
211- CancellationToken ctk = default
212- ) where T : class
213- {
214- var ( connection , wasClosed ) = await context . GetConnection ( ctk ) ;
215-
216- var ( tableName , _) = await PerformBulkInsertAsync ( context , entities , options , tempTableRequired : true , ctk : ctk ) ;
217-
218- var result = await CopyFromTempTablePrimaryKeyAsync < T > ( context , connection , tableName , options , ctk ) ;
219-
220- if ( wasClosed )
221- {
222- await connection . CloseAsync ( ) ;
223- }
224-
225- return result ;
226- }
227-
228132 public async Task BulkInsertWithoutReturnAsync < T > (
229133 DbContext context ,
230134 IEnumerable < T > entities ,
@@ -265,32 +169,7 @@ public async Task BulkInsertWithoutReturnAsync<T>(
265169
266170 var ( connection , wasClosed ) = await context . GetConnection ( ctk ) ;
267171
268- if ( options . Recursive )
269- {
270- // Insert children first
271- var navigationProperties = context . GetNavigationProperties ( typeof ( T ) ) ;
272-
273- foreach ( var navigationProperty in navigationProperties )
274- {
275- var itemType = navigationProperty . ClrType ;
276- var tupleType = typeof ( KeyValuePair < , > ) . MakeGenericType ( typeof ( long ) , itemType ) ;
277-
278- // Call GetChildrenEntities with reflection because the type is not known at compile time
279- var allChildren = GetChildrenMethod . MakeGenericMethod ( typeof ( T ) ) . Invoke ( this , [ entities , navigationProperty ] ) as IEnumerable < KeyValuePair < long , object > > ;
280-
281- // Cast the IEnumerable to the correct type
282- var items = new List < KeyValuePair < long , object > > ( allChildren ) ;
283- // var itemsCasted = CastMethod.MakeGenericMethod(tupleType).Invoke(null, [items]);
284- // var items = allChildren.Cast<KeyValuePair<long, object>>();
285-
286- // Call BulkInsertWithPrimaryKeyAsync to insert elements and get their primary key values
287- var bulkInsert = BulkInsertPkMethod . MakeGenericMethod ( tupleType ) ;
288-
289- var pkValues = await ( bulkInsert . Invoke ( this , [ context , items , options , ctk ] ) as Task < List < KeyValuePair < long , object [ ] > > > ) ! ;
290- }
291- }
292-
293- var tableName = tempTableRequired || options . Recursive
172+ var tableName = tempTableRequired
294173 ? await CreateTableCopyAsync < T > ( context , connection , ctk )
295174 : GetEscapedTableName ( context , typeof ( T ) ) ;
296175
@@ -313,32 +192,6 @@ public async Task BulkInsertWithoutReturnAsync<T>(
313192 protected abstract Task BulkInsert < T > ( DbContext context , IEnumerable < T > entities ,
314193 string tableName , PropertyAccessor [ ] properties , BulkInsertOptions options , CancellationToken ctk ) where T : class ;
315194
316- public IEnumerable < KeyValuePair < long , object > > GetChildrenEntities < T > ( IEnumerable < T > entities , INavigation navigationProperty ) where T : class
317- {
318- var navProp = navigationProperty . PropertyInfo ;
319- var isCollection = navigationProperty . IsCollection ;
320- long index = 0 ;
321-
322- foreach ( var e in entities )
323- {
324- var value = navProp ! . GetValue ( e ) ;
325-
326- if ( isCollection && value is IEnumerable enumerable )
327- {
328- foreach ( var childEntity in enumerable )
329- {
330- yield return new KeyValuePair < long , object > ( index , childEntity ) ;
331- }
332- }
333- else if ( value != null )
334- {
335- yield return new KeyValuePair < long , object > ( index , value ) ;
336- }
337-
338- index ++ ;
339- }
340- }
341-
342195 /// <summary>
343196 /// Escapes a schema and table name using database-specific delimiters.
344197 /// </summary>
0 commit comments