Esempio n. 1
0
        /// <summary>
        /// Processes the given work units.
        /// </summary>
        /// <param name="units"></param>
        public void Process(WorkUnitCollection units, bool trace = false, IOperationItem operation = null, bool outsideTransaction = false, ITimingBucket timings = null)
        {
            if (units == null)
            {
                throw new ArgumentNullException("units");
            }
            if (units.Count == 0)
            {
                return;
            }

            // operation...
            if (timings == null)
            {
                timings = NullTimingBucket.Instance;
            }
            if (operation == null)
            {
                operation = NullOperationItem.Instance;
            }

            // mbr - 02-10-2007 - case 827 - notify outside...
            // mbr - 2014-11-30 - changed this to load up the statements...
            var touchedEts          = new List <EntityType>();
            var anyNeedsTransaction = units.Count > 1;
            var context             = new WorkUnitProcessingContext(timings);

            using (timings.GetTimer("Count"))
            {
                foreach (IWorkUnit unit in units)
                {
                    ISaveChangesNotification notification = unit.Entity as ISaveChangesNotification;
                    if (notification != null)
                    {
                        notification.BeforeSaveChangesOutTransaction(unit);
                    }

                    // add...
                    if (!(touchedEts.Contains(unit.EntityType)))
                    {
                        touchedEts.Add(unit.EntityType);
                    }

                    // add...
                    if (unit.NeedsTransaction && !(anyNeedsTransaction))
                    {
                        anyNeedsTransaction = true;
                    }
                }
            }

            // mbr - 26-11-2007 - get a manager for this thread...
            IWorkUnitTransactionManager manager = null;

            using (timings.GetTimer("Initialize manager"))
            {
                if (outsideTransaction)
                {
                    manager = new OutsideTransactionWorkUnitProcessorTransactionManager();
                }
                else
                {
                    //manager = WorkUnitProcessorTransactionManager.Current;

                    // mbr - 2014-11-30 - we only want to use transactions if we are in a tranaction. the old
                    // approach created a transaction just for single row inserts, which turned out created
                    // quite a slowdown...
                    if (anyNeedsTransaction)
                    {
                        manager = WorkUnitProcessorTransactionManager.Current;
                    }
                    else
                    {
                        manager = WorkUnitProcessorNullTransactionManager.Current;
                    }
                }
                if (manager == null)
                {
                    throw new InvalidOperationException("manager is null.");
                }

                // initialise the manager...
                manager.Initialize();
            }

            try
            {
                // mbr - 26-11-2007 - now done in the manager...
//				if(connection == null)
//					connection = Database.CreateConnection(units[0].EntityType.DatabaseName);

                // mbr - 26-11-2007 - don't do transactions here (the manager will do it)...
//				connection.BeginTransaction();
                try
                {
                    // reset the bag...
                    using (timings.GetTimer("Reset"))
                        context.ResetBag();

                    // run...
                    operation.ProgressMaximum = units.Count;
                    operation.ProgressValue   = 0;

                    // mbr - 06-09-2007 - for c7 - the "before" event can replace the work unit.  (done by changing the entity and regenerating.)
                    //foreach(IWorkUnit unit in units)
                    for (int index = 0; index < units.Count; index++)
                    {
                        using (var child = timings.GetChildBucket("Execute"))
                        {
                            // get a connection to use here...
                            IConnection connection = null;
                            using (child.GetTimer("Connect"))
                            {
                                connection = manager.GetConnection(units[index]);
                                if (connection == null)
                                {
                                    throw new InvalidOperationException("connection is null.");
                                }

                                // set...
                                context.SetConnection(connection);
                            }

                            // get the unit...
                            IWorkUnit unit = units[index];
                            try
                            {
                                if (trace)
                                {
                                    this.LogInfo(() => string.Format("Running unit '{0}'...", unit));
                                }

                                ISaveChangesNotification notification = unit.Entity as ISaveChangesNotification;
                                using (child.GetTimer("NotifyPre"))
                                {
                                    // before...
                                    if (notification != null)
                                    {
                                        // mbr - 02-10-2007 - case 827 - changed interface.
                                        //								IWorkUnit newUnit = notification.BeforeSaveChanges(unit);
                                        IWorkUnit newUnit = notification.BeforeSaveChangesInTransaction(unit, connection);

                                        // patch it..
                                        if (newUnit != unit)
                                        {
                                            units[index] = newUnit;
                                            unit         = newUnit;
                                        }
                                    }
                                }

                                // run it...
                                using (var childChild = child.GetChildBucket("Process"))
                                    unit.Process(context, childChild);

                                // set...
                                using (child.GetTimer("Results"))
                                    unit.SetResultsBag(context.Bag);

                                // mbr - 10-10-2007 - for c7 - do reconciliation here...
                                using (child.GetTimer("Reconcile"))
                                {
                                    WorkUnitCollection forReconciliation = new WorkUnitCollection();
                                    forReconciliation.Add(unit);
                                    unit.EntityType.Persistence.ReconcileWorkUnitProcessorResults(forReconciliation);
                                }

                                // mbr - 02-10-2007 - case 827 - call...
                                using (child.GetTimer("NotifyPost"))
                                {
                                    if (notification != null)
                                    {
                                        notification.AfterSaveChangesInTransaction(unit, connection);
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                throw new InvalidOperationException(string.Format(Cultures.Exceptions, "Failed when processing '{0}'.", unit), ex);
                            }

                            // next...
                            operation.IncrementProgress();
                        }
                    }

                    // mbr - 26-11-2007 - it's the manager that needs to commit...
//					connection.Commit();

                    using (timings.GetTimer("Commit"))
                        manager.Commit();
                }
                catch (Exception ex)
                {
                    // rollback...
                    try
                    {
                        // mbr - 26-11-2007 - it's the manager that needs to rollback...
//						connection.Rollback();
                        manager.Rollback(ex);
                    }
                    catch (Exception rollbackEx)
                    {
                        // mbr - 26-11-2007 - added.
                        if (this.Log.IsWarnEnabled)
                        {
                            this.Log.Warn("A further exception occurred whilst rolling back the transaction.", rollbackEx);
                        }
                    }

                    // throw...
                    throw new InvalidOperationException("Failed to process work units.", ex);
                }
            }
            finally
            {
                // mbr - 26-11-2007 - get the manager to tear down...
//				if(connection != null)
//					connection.Dispose();
                using (timings.GetTimer("Dispose"))
                    manager.Dispose();

                // mbr - 2010-04-19 - invalidate the caches...
                //EntityCache.Invalidate(touchedEts);

                // flag...
                foreach (IWorkUnit unit in units)
                {
                    ISaveChangesNotification notification = unit.Entity as ISaveChangesNotification;
                    if (notification != null)
                    {
                        notification.AfterSaveChangesOutTransaction(unit);
                    }
                }
            }
        }