예제 #1
0
        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;
            }
        }