internal static int CommitTransaction <TEntity>(DbContext context, IEnumerable <TEntity> entities, OperationType operation) where TEntity : class { // Retrieve entity type IEntityType entityType = context.Model.FindEntityType(typeof(TEntity)); EntityInfo entityMapping = new EntityInfo(entityType); // Sample random table looks like this [_VssBuildDefinition_02da3b] string randomTableName = $"[_{entityMapping.TableName}_{Guid.NewGuid().ToString().Substring(0, 6)}]"; // Build staging table sql command string stagingTableCommand = BulkOperationHelper.BuildStagingTableCommand(entityMapping, randomTableName, operation); // Open connection if it's closed if (context.Database.GetDbConnection().State == ConnectionState.Closed) { context.Database.GetDbConnection().Open(); } // If caller does not specify a transaction we create an internal transaction IDbContextTransaction internalTrasaction = null; if (context.Database.CurrentTransaction == null) { internalTrasaction = context.Database.BeginTransaction(); } // No entities to commit if (!entities.Any()) { return(0); } // Final step is to create staging table and merge data into final table try { // Create staging table and insert data into staging table BulkOperationHelper.ExecuteSqlCommandNonQuery(context, stagingTableCommand); BulkOperationHelper.BulkInsertToTable(entityMapping, context, entities.ToList(), randomTableName, operation); // Merge staging table data into final table and commit string mergeCommand = BulkOperationHelper.BuildMergeCommand(entityMapping, randomTableName, operation); int result = BulkOperationHelper.ExecuteSqlCommandNonQuery(context, mergeCommand); // Only commit internal transaction and let caller's transaction commit on their own internalTrasaction?.Commit(); // Return the number of records affected return(result); } catch (Exception) { // If anything goes wrong, we roll back to undo the operation internalTrasaction?.Rollback(); context.Database.CurrentTransaction?.GetDbTransaction().Rollback(); throw; } }