/// <summary>
        /// 回退流程到某个活动
        /// 说明:将当前活动实例回退到,某个目标活动。
        /// 具体步骤:
        /// 1、寻找目标活动实例。
        /// 2、将目标活动及后续已完成的活动实例及工作项终止。
        /// 3、终止当前活动实例及工作项。(注:为记录当前执行人再终止一次)
        /// 4、重新启动可退回活动。
        /// </summary>
        /// <param name="user"></param>
        /// <param name="srcActInst"></param>
        /// <param name="destActivity"></param>
        public void RollbackActivity(IUser user, ActivityInst srcActInst, Activity destActivity)
        {
            var destActInst = repository.Query<ActivityInst>().FirstOrDefault(ai => ai.ProcessInstID == srcActInst.ProcessInstID && ai.RollbackFlag == 0 && ai.ActivityDefID == destActivity.ID);

            if (destActInst != null)
            {
                DateTime createTime = DateTime.Now;
                UnitOfWork.ExecuteWithTrans<ProcessDef>(() =>
                {
                    //终止destActivity所有的后续已执行的的活动实例
                    TerminateSelfAndOutActivity(destActInst.ProcessInstID, destActivity);

                    //将当前活动实例的工作项终止(将终止人设为当前用户)
                    var workItems = Persistence.GetWorkItems(srcActInst.ID);
                    foreach (var wi in workItems)
                    {
                        wi.CurrentState = (short)WorkItemStatus.Terminated;
                        wi.ExecutorName = user.Name;
                        wi.Executor = user.ID;
                        wi.ExecuteTime = createTime;
                        log.Info(string.Format("终止工作项{0}-{1}", wi.ID, wi.Name));
                        repository.SaveOrUpdate(wi);

                    }
                    //将当前活动实例终止
                    srcActInst.CurrentState = (short)ActivityInstStatus.Terminated;
                    srcActInst.RollbackFlag = 1;
                    srcActInst.EndTime = createTime;
                    log.Info(string.Format("终止活动实例{0}-{1}", srcActInst.ID, srcActInst.Name));
                    repository.SaveOrUpdate(srcActInst);

                    //将目标活动实例的工作项重置为待执行
                    workItems = Persistence.GetWorkItems(destActInst.ID);
                    foreach (var wi in workItems)
                    {
                        wi.CurrentState = (short)WorkItemStatus.WaitExecute;
                        //wi.ExecutorName = user.Name;
                        //wi.Executor = user.ID;
                        // wi.ExecuteTime = null;// DateTime.MaxValue;
                        log.Info(string.Format("启动工作项{0}-{1}", wi.ID, wi.Name));
                        repository.SaveOrUpdate(wi);
                    }

                    //将目标活动实例状态置为未开始
                    destActInst.CurrentState = (short)ActivityInstStatus.NoStart;
                    destActInst.RollbackFlag = 0;
                    log.Info(string.Format("启动活动实例{0}-{1}", destActInst.ID, destActInst.Name));
                    repository.SaveOrUpdate(destActInst);

                    ProcessInst processInst = repository.GetDomain<ProcessInst>(srcActInst.ProcessInstID);
                    Domain.Transition transition = new Domain.Transition()
                    {
                        ID = IdGenerator.NewComb().ToString(),
                        DestActID = destActivity.ID,
                        DestActInstID = destActInst.ID,
                        DestActInstName = destActInst.Name,
                        DestActName = destActivity.Name,
                        ProcessInstID = srcActInst.ProcessInstID,
                        ProcessInstName = processInst.Name,
                        SrcActID = srcActInst.ActivityDefID,
                        SrcActInstID = srcActInst.ID,
                        SrcActInstName = srcActInst.Name,
                        SrcActName = srcActInst.Name,
                        TransTime = createTime
                    };
                    repository.SaveOrUpdate(transition);

                    TransControl transControl = new TransControl()
                    {
                        ID = IdGenerator.NewComb().ToString(),
                        DestActID = destActivity.ID,
                        DestActName = destActivity.Name,
                        ProcessInstID = srcActInst.ProcessInstID,
                        SrcActID = srcActInst.ActivityDefID,
                        SrcActName = srcActInst.Name,
                        TransTime = createTime,
                        TransWeight = 100
                    };
                    repository.SaveOrUpdate(transControl);
                });
            }
        }
        /// <summary>
        /// 获取一个流程实例
        /// </summary>
        /// <param name="processInstID">流程实例ID</param>
        /// <returns></returns>
        private ProcessInst GetToRunProcessInst(string processInstID, IUser user)
        {
            ProcessInst processInst = Persistence.GetProcessInst(processInstID);
            ProcessDefine processDefine = GetProcessDefine(processInst.ProcessDefID);
            string processDefID = processInst.ProcessDefID;

            //如果流程还未启动,产生一个活动实例
            if (processInst.CurrentState == (short)ProcessInstStatus.NoStart)
            {
                Activity srcActivity = processDefine.StartActivity;
                ActivityInst srcActInst = Persistence.GetActivityInsts(processInstID, srcActivity.ID, ActivityInstStatus.Compeleted)[0];
                IList<Activity> destActivities = Persistence.GetOutActivities(processDefID, srcActivity.ID);

                UnitOfWork.ExecuteWithTrans<ProcessInst>(() =>
                {
                    foreach (var destActivity in destActivities)
                    {
                        DateTime startTime = DateTime.Now.AddSeconds(-1);
                        ActivityInst destActInst = new ActivityInst()
                        {
                            ActivityDefID = destActivity.ID,
                            CurrentState = (short)ActivityInstStatus.NoStart,
                            ID = IdGenerator.NewComb().ToString(),
                            CreateTime = startTime,
                            Description = destActivity.Description,
                            EndTime = WFUtil.MaxDate,
                            Name = destActivity.Name,
                            ProcessInstID = processInstID,
                            RollbackFlag = 0,
                            StartTime = startTime,
                            SubProcessInstID = string.Empty,
                            Type = (short)destActivity.ActivityType.Cast<ActivityType>(ActivityType.ManualActivity)
                        };

                        Domain.Transition transition = new Domain.Transition()
                        {
                            ID = IdGenerator.NewComb().ToString(),
                            DestActID = destActivity.ID,
                            DestActInstID = destActInst.ID,
                            DestActInstName = destActInst.Name,
                            DestActName = destActivity.Name,
                            ProcessInstID = processInstID,
                            ProcessInstName = processInst.Name,
                            SrcActID = srcActivity.ID,
                            SrcActInstID = srcActInst.ID,
                            SrcActInstName = srcActInst.Name,
                            SrcActName = srcActivity.Name,
                            TransTime = startTime
                        };

                        TransControl transControl = new TransControl()
                        {
                            ID = IdGenerator.NewComb().ToString(),
                            DestActID = destActivity.ID,
                            DestActName = destActivity.Name,
                            ProcessInstID = processInst.ID,
                            SrcActID = srcActivity.ID,
                            SrcActName = srcActivity.Name,
                            TransTime = startTime,
                            TransWeight = 100
                        };

                        if (destActivity is ManualActivity)
                        {
                            ManualActivity ma = destActivity as ManualActivity;
                            WorkItem wi = new WorkItem()
                            {
                                ID = IdGenerator.NewComb().ToString(),
                                ActionMask = string.Empty,
                                ActionURL = ma.CustomURL.SpecifyURL,
                                ActivityInstID = destActInst.ID,
                                ActivityInstName = destActInst.Name,
                                AllowAgent = (short)(ma.AllowAgent ? 1 : 0),
                                BizState = (short)WorkItemBizStatus.Common,
                                CreateTime = startTime,
                                Creator = user.ID,
                                CreatorName = user.Name,
                                CurrentState = (short)WorkItemStatus.WaitExecute,
                                Description = destActInst.Description,
                                EndTime = WFUtil.MaxDate,
                                Executor = string.Empty,
                                ExecutorName = string.Empty,
                                IsTimeOut = 0,
                                Name = destActInst.Name,
                                Participant = string.Empty,
                                ProcessID = processDefID,
                                ProcessInstID = processInst.ID,
                                ProcessInstName = processInst.Name,
                                ProcessName = processDefine.Name,
                                RemindTime = WFUtil.MaxDate,
                                RootProcessInstID = string.Empty,
                                StartTime = startTime,
                                TimeOutTime = WFUtil.MaxDate,
                                Type = destActInst.Type
                            };

                            //foreach (var participantor in ma.Participant.Participantors)
                            //{
                            //    Domain.Participant participant = new Domain.Participant()
                            //    {
                            //        ID = IdGenerator.NewComb().ToString(),
                            //        CreateTime = createTime,
                            //        DelegateType = (short)DelegateType.Sponsor,
                            //        Name = participantor.Name,
                            //        ParticipantID = participantor.ID,
                            //        ParticipantIndex = participantor.SortOrder,
                            //        ParticipantType = (short)participantor.ParticipantorType.Cast<ParticipantorType>(ParticipantorType.Person),
                            //        PartiInType = (short)PartiInType.Exe,
                            //        WorkItemID = wi.ID,
                            //        WorkItemState = (short)wi.CurrentState
                            //    };

                            //    repository.SaveOrUpdate(participant);
                            //}

                            Domain.Participant participant = new Domain.Participant()
                            {
                                ID = IdGenerator.NewComb().ToString(),
                                CreateTime = startTime,
                                DelegateType = (short)DelegateType.Sponsor,
                                Name = user.Name,
                                ParticipantID = user.ID,
                                ParticipantIndex = 1,
                                ParticipantType = (short)ParticipantorType.Person,
                                PartiInType = (short)PartiInType.Exe,
                                WorkItemID = wi.ID,
                                WorkItemState = (short)wi.CurrentState
                            };

                            repository.SaveOrUpdate(participant);

                            repository.SaveOrUpdate(wi);
                        }

                        srcActInst.CurrentState = (short)ActivityInstStatus.Compeleted;
                        repository.SaveOrUpdate(srcActInst);
                        repository.SaveOrUpdate(destActInst);
                        repository.SaveOrUpdate(transition);
                        repository.SaveOrUpdate(transControl);
                    }
                });
            }

            return processInst;
        }
        /// <summary>
        /// Passes a transaction to the cashier
        /// </summary>
        /// <param name="counterNo"></param>
        /// <returns></returns>
        public async Task <Tuple <string, int> > PassTransactionToCashier(int counterNo)
        {
            using (var transaction = await _context.Database.BeginTransactionAsync())
            {
                var counter = await _context.Counters
                              .AsNoTracking()
                              .FirstOrDefaultAsync(x => x.COunterNo == counterNo);

                if (counter == null)
                {
                    return(new Tuple <string, int>("", 0));
                }

                // find the transaction to be passed
                var trans = await _context.Transactions
                            .Include(x => x.TransPool)
                            .FirstOrDefaultAsync(x => x.TransactionId == counter.TransactionId);

                // Make sure that the transaction is good for the current day
                if (trans == null)
                {
                    return(new Tuple <string, int>("", 0));
                }

                var prevTrans = await _context.Transactions
                                .FirstOrDefaultAsync(x => x.TransactionId == trans.PrevId);

                var nextTrans = await _context.Transactions
                                .FirstOrDefaultAsync(x => x.TransactionId == trans.NextId);

                // Determine if the version is in sync with the database
                _context.Entry(trans).Property(x => x.RowVersion2).OriginalValue =
                    trans.RowVersion2;

                // Find if there's an existing Trans control for payments
                var cashierTransControl = await _context.TransControls
                                          .Include(x => x.CounterType)
                                          .FirstOrDefaultAsync(x => x.CounterType.IsEndpoint);

                // Create a transaction control if not found
                if (cashierTransControl == null)
                {
                    var cashierCounterType = await _context.CounterTypes
                                             .AsNoTracking()
                                             .FirstOrDefaultAsync(x => x.IsEndpoint);

                    var newCashierTransControl = new TransControl
                    {
                        CounterTypeId = cashierCounterType.CounterTypeId,
                        IsSpecial     = false
                    };

                    await _context.TransControls.AddAsync(newCashierTransControl);

                    await _context.SaveChangesAsync();

                    cashierTransControl = newCashierTransControl;
                }

                // find if there's an existing trans pool for payments
                var cashierTransPool = await _context.TransPools
                                       .FirstOrDefaultAsync(x => x.TransControlId == cashierTransControl.TransControlId &&
                                                            x.TransactionDate.Date == DateTime.Now.Date &&
                                                            x.IsSpecial == trans.TransPool.IsSpecial);

                // Create a trans pool if not found
                if (cashierTransPool == null)
                {
                    var newCashierTransPool = new TransPool
                    {
                        TransControlId  = cashierTransControl.TransControlId,
                        IsSpecial       = trans.TransPool.IsSpecial,
                        First           = 1,
                        Last            = 0,
                        TransactionDate = DateTime.Now.Date
                    };

                    await _context.TransPools.AddAsync(newCashierTransPool);

                    await _context.SaveChangesAsync();

                    cashierTransPool = newCashierTransPool;
                }

                // Find the tail of the main chain of payments
                var cashierTailTrans = await _context.Transactions
                                       .FirstOrDefaultAsync(x => !x.IsServed &&
                                                            x.TransPool.TransPoolId == cashierTransPool.TransPoolId &&
                                                            x.NextId == null);

                if (cashierTailTrans != null)
                {
                    // Determine if the version of object is in sync with what with the database
                    _context.Entry(cashierTailTrans).Property(x => x.RowVersion2).OriginalValue =
                        cashierTailTrans.RowVersion2;

                    // establish the link between the cashier's tail and the passed transaction
                    cashierTailTrans.NextId = trans.TransactionId;
                    trans.PrevId            = cashierTailTrans.TransactionId;
                    trans.NextId            = null; // Since this serves as the new tail of the cashier pool chain

                    _context.Transactions.Update(cashierTailTrans);
                }
                else
                {
                    // Happens when the transaction is the first one in the cashier
                    trans.NextId = null;
                    trans.PrevId = null;
                }

                // Sever ties between the neighboring transactions and the passed transaction
                var transName = "";
                var prioNo    = 0;

                if (prevTrans == null && nextTrans == null)
                {
                    counter.TransactionId = null;
                }

                if (prevTrans != null && nextTrans != null)
                {
                    _context.Entry(prevTrans).Property(x => x.RowVersion2).OriginalValue =
                        prevTrans.RowVersion2;
                    _context.Entry(nextTrans).Property(x => x.RowVersion2).OriginalValue =
                        nextTrans.RowVersion2;

                    nextTrans.PrevId = prevTrans.TransactionId;
                    prevTrans.NextId = nextTrans.TransactionId;

                    // Pass the next transaction to the counter
                    counter.TransactionId = nextTrans.TransactionId;
                    transName             = nextTrans.Name;
                    prioNo = nextTrans.PrioNo;

                    // Update the prev trans and next trans
                    _context.Transactions.Update(prevTrans);
                    _context.Transactions.Update(nextTrans);
                }

                // If there is a previous transaction and no next trans
                if (prevTrans != null && nextTrans == null)
                {
                    _context.Entry(prevTrans).Property(x => x.RowVersion2).OriginalValue =
                        prevTrans.RowVersion2;

                    prevTrans.NextId = null;

                    // Pass the previous transaction to the counter
                    counter.TransactionId = prevTrans.TransactionId;

                    _context.Transactions.Update(prevTrans);
                }

                // If there is no prev transaction but there is a next transaction
                if (prevTrans == null && nextTrans != null)
                {
                    _context.Entry(nextTrans).Property(x => x.RowVersion2).OriginalValue =
                        nextTrans.RowVersion2;

                    nextTrans.PrevId = null;

                    // Pass the next transaction to the counter
                    counter.TransactionId = nextTrans.TransactionId;
                    transName             = nextTrans.Name;
                    prioNo = nextTrans.PrioNo;

                    _context.Transactions.Update(nextTrans);
                }

                // Transfer the pool to the cashier's pool
                trans.TransPoolId     = cashierTransPool.TransPoolId;
                trans.IsServed        = false;
                trans.DateTimeOrdered = DateTime.Now; // The time date and time it is transfered

                _context.Counters.Update(counter);
                _context.Transactions.Update(trans);

                await _context.SaveChangesAsync();

                transaction.Commit();

                return(new Tuple <string, int>(transName, prioNo));
            }
        }
        /// <summary>
        /// Returns the next number
        /// Updates the transaction
        /// Creates a transaction if there's none
        /// </summary>
        /// <returns></returns>
        public async Task <Tuple <string, string, int> > PrintPrioNo(int counterTypeId, bool isSpecial)
        {
            using (var transaction =
                       await _context.Database.BeginTransactionAsync())
            {
                var counterType = await _context.CounterTypes
                                  .AsNoTracking()
                                  .FirstOrDefaultAsync(x => x.CounterTypeId == counterTypeId);

                if (counterType == null)
                {
                    return(new Tuple <string, string, int>("", "", 0));
                }

                // find out if there's an existing transpool
                var transControl = await _context.TransControls
                                   .FirstOrDefaultAsync(x =>
                                                        x.CounterTypeId == counterType.CounterTypeId);

                // Create a transaction controller if there's not anything found
                if (transControl == null)
                {
                    var newTransControl = new TransControl
                    {
                        CounterTypeId = counterType.CounterTypeId,
                        IsSpecial     = false
                    };

                    await _context.TransControls.AddAsync(newTransControl);

                    await _context.SaveChangesAsync();

                    transControl = newTransControl;
                }

                // find out if there's an existing trans pool
                var transPool = await _context.TransPools
                                .FirstOrDefaultAsync(x =>
                                                     x.TransControlId == transControl.TransControlId &&
                                                     x.IsSpecial == isSpecial &&
                                                     x.TransactionDate.Date == DateTime.Now.Date);

                // Create new transaction pool if there's nothing found
                if (transPool == null)
                {
                    var newTransPool = new TransPool
                    {
                        TransControlId  = transControl.TransControlId,
                        IsSpecial       = isSpecial,
                        TransactionDate = DateTime.Now
                    };

                    if (transControl.IsSpecial == null)
                    {
                        transControl.IsSpecial = false;
                    }

                    _context.TransControls.Update(transControl);

                    await _context.TransPools.AddAsync(newTransPool);

                    await _context.SaveChangesAsync(); // needed this to generate Id

                    transPool = newTransPool;
                }

                // Find out if there's any previous transaction that was printed
                var trans = await _context.Transactions
                            .FirstOrDefaultAsync(x => x.NextId == null &&
                                                 x.TransPoolId == transPool.TransPoolId &&
                                                 !x.IsServed);

                // Create new transaction and link it to the previous one if there's any
                if (trans != null)
                {
                    // Determine if the objects' version are in sync with what's in the database
                    _context.Entry(trans).Property(x => x.RowVersion2).OriginalValue = trans.RowVersion2;

                    // Save the last number generated
                    transPool.Last = transPool.Last + 1;

                    // increment the prio number before creating the new transaction
                    var newTransRes = await CreateNewTransaction(transPool.TransPoolId,
                                                                 transPool.Last, isSpecial, counterType.CounterShortName);

                    var newTrans = newTransRes.Item2;

                    _context.Entry(newTrans).Property(x => x.RowVersion2).OriginalValue = newTrans.RowVersion2;

                    trans.NextId    = newTrans.TransactionId;
                    newTrans.PrevId = trans.TransactionId;

                    _context.TransPools.Update(transPool);
                    _context.Transactions.Update(trans);
                    _context.Transactions.Update(newTrans);

                    await _context.SaveChangesAsync();

                    transaction.Commit();

                    return(new Tuple <string, string, int>(counterType.CounterName,
                                                           newTransRes.Item1, newTransRes.Item2.PrioNo));
                }

                // Update the trans pool to save the first and last number
                transPool.First = transPool.First + 1;
                transPool.Last  = transPool.Last + 1;

                var newTransRes2 = await CreateNewTransaction(transPool.TransPoolId,
                                                              transPool.Last, isSpecial, counterType.CounterShortName);

                if (newTransRes2.Item2 == null || newTransRes2.Item2.TransactionId == 0)
                {
                    return(new Tuple <string, string, int>("", "", 0));
                }

                _context.TransPools.Update(transPool);

                await _context.SaveChangesAsync();

                transaction.Commit(); // Commit all to the database

                return(new Tuple <string, string, int>(counterType.CounterName,
                                                       newTransRes2.Item1,
                                                       newTransRes2.Item2.PrioNo));
            }
        }
        private async Task <Transaction> NextWithNoTransaction(Counter counter,
                                                               TransControl transControl)
        {
            // Find the special transaction pool, if not found, get the counterpart
            var curTransPool = await _context.TransPools
                               .FirstOrDefaultAsync(x => x.TransControlId == transControl.TransControlId &&
                                                    x.TransactionDate.Date == DateTime.Now.Date &&
                                                    x.IsSpecial == !transControl.IsSpecial) ?? await _context.TransPools
                               .FirstOrDefaultAsync(x => x.TransControlId == transControl.TransControlId &&
                                                    x.TransactionDate.Date == DateTime.Now.Date &&
                                                    x.IsSpecial == transControl.IsSpecial);

            if (curTransPool == null)
            {
                return(null);
            }

            // Remove the newTrans from the main chain
            var newTrans = await _context.Transactions
                           .FirstOrDefaultAsync(x => x.TransPoolId == curTransPool.TransPoolId &&
                                                x.PrevId == null &&
                                                !x.IsServed);

            // Add the newTrans to the counter's chain
            // If the next transaction is not found, try getting a transaction from the next pool
            if (newTrans == null)
            {
                var pool = await _context.TransPools
                           .FirstOrDefaultAsync(x => x.TransControlId == transControl.TransControlId &&
                                                x.TransactionDate.Date == DateTime.Now.Date &&
                                                x.IsSpecial == !curTransPool.IsSpecial);

                if (pool == null)
                {
                    return(null);
                }

                newTrans = await _context.Transactions
                           .FirstOrDefaultAsync(x => x.TransPoolId == pool.TransPoolId &&
                                                !x.IsServed &&
                                                x.PrevId == null);

                if (newTrans == null)
                {
                    return(null);
                }

                curTransPool = pool;
            }

            var newNextTrans = await _context.Transactions
                               .FirstOrDefaultAsync(x => x.TransactionId == newTrans.NextId);

            // Remove the new trans from the main chain
            if (newNextTrans != null)
            {
                _context.Entry(newTrans).Property(x => x.RowVersion2).OriginalValue =
                    newTrans.RowVersion2;
                _context.Entry(newNextTrans).Property(x => x.RowVersion2).OriginalValue =
                    newNextTrans.RowVersion2;

                newTrans.NextId     = null;
                newNextTrans.PrevId = null;

                _context.Transactions.Update(newNextTrans);
            }

            newTrans.IsServed = true;

            counter.TransactionId  = newTrans.TransactionId;
            transControl.IsSpecial = curTransPool.IsSpecial;

            _context.TransControls.Update(transControl);
            _context.Counters.Update(counter);
            _context.Transactions.Update(newTrans);

            return(newTrans);
        }
        private async Task <Transaction> NextWithExistingTransaction(Counter counter,
                                                                     Transaction curtrans, TransControl transControl)
        {
            // If there's already an existing next transaction
            if (curtrans.NextTrans != null)
            {
                counter.TransactionId = curtrans.NextId;

                _context.Counters.Update(counter);
                await _context.SaveChangesAsync();

                return(curtrans.NextTrans);
            }

            // find the next pool, use the current pool if the next pool is not found
            var nextPool = await _context.TransPools
                           .FirstOrDefaultAsync(x => x.TransControlId == transControl.TransControlId &&
                                                x.TransactionDate.Date == DateTime.Now.Date &&
                                                x.IsSpecial == !transControl.IsSpecial.Value) ??
                           await _context.TransPools
                           .FirstOrDefaultAsync(x => x.TransControlId == transControl.TransControlId &&
                                                x.TransactionDate.Date == DateTime.Now.Date &&
                                                x.IsSpecial == transControl.IsSpecial.Value);


            var newTrans = await _context.Transactions
                           .FirstOrDefaultAsync(x => x.TransPoolId == nextPool.TransPoolId &&
                                                !x.IsServed &&
                                                x.PrevId == null); // Find the transaction at the tail of the main chain

            // Use the current pool instead to get the new transaction
            if (newTrans == null)
            {
                var pool = await _context.TransPools
                           .FirstOrDefaultAsync(x => x.TransControlId == transControl.TransControlId &&
                                                x.TransactionDate.Date == DateTime.Now.Date &&
                                                x.IsSpecial == transControl.IsSpecial.Value);

                if (pool == null)
                {
                    return(null);
                }

                newTrans = await _context.Transactions
                           .FirstOrDefaultAsync(x => x.TransPoolId == pool.TransPoolId &&
                                                !x.IsServed &&
                                                x.PrevId == null);  // Find the transaction at the tail of the main chain

                nextPool = pool;
            }

            if (newTrans == null) // return null if there's really no transaction
            {
                return(null);
            }

            var newNextTrans = await _context.Transactions
                               .FirstOrDefaultAsync(x => x.TransactionId == newTrans.NextId);

            // The next transaction's next one will be the new tail of the main tail
            if (newNextTrans != null)
            {
                _context.Entry(newTrans).Property(x => x.RowVersion2).OriginalValue =
                    newTrans.RowVersion2;
                _context.Entry(newNextTrans).Property(x => x.RowVersion2).OriginalValue =
                    newNextTrans.RowVersion2;

                newNextTrans.PrevId = null;
                newTrans.NextId     = null;

                _context.Transactions.Update(
                    newNextTrans);
            }

            newTrans.IsServed = true;

            // Link the new trans to the new chain belonging to a window
            curtrans.NextId = newTrans.TransactionId;
            newTrans.PrevId = curtrans.TransactionId;

            counter.TransactionId  = newTrans.TransactionId;
            transControl.IsSpecial = nextPool.IsSpecial;

            _context.TransControls.Update(transControl);
            _context.Counters.Update(counter);
            _context.Transactions.Update(newTrans);
            _context.Transactions.Update(curtrans);

            return(newTrans);
        }
        /// <summary>
        /// 产生迁移活动
        /// </summary>
        /// <param name="srcActInst"></param>
        public void RouteActivityInst(ActivityInst srcActInst)
        {
            Activity srcActivity = Context.ProcessDefine.Activities.FirstOrDefault(a => a.ID == srcActInst.ActivityDefID);
            IList<Activity> activateActivities = GetActivateActivities(Context.ProcessInst.ProcessDefID, srcActInst);
            string processInstID = Context.ProcessInst.ID;
            string processDefID = Context.ProcessInst.ProcessDefID;

            UnitOfWork.ExecuteWithTrans<WorkItem>(() =>
            {
                foreach (var destActivity in activateActivities)
                {
                    DateTime createTime = DateTime.Now;
                    ActivityInst destActInst = new ActivityInst()
                    {
                        ActivityDefID = destActivity.ID,
                        CurrentState = (short)(destActivity.ActivityType == ActivityType.EndActivity || destActivity.ActivityType == ActivityType.AutoActivity ? ActivityInstStatus.Compeleted : ActivityInstStatus.NoStart),
                        ID = IdGenerator.NewComb().ToString(),
                        CreateTime = createTime,
                        Description = destActivity.Description,
                        EndTime = WFUtil.MaxDate,
                        Name = destActivity.Name,
                        ProcessInstID = processInstID,
                        RollbackFlag = 0,
                        StartTime = createTime,
                        SubProcessInstID = string.Empty,
                        Type = (short)destActivity.ActivityType.Cast<ActivityType>(ActivityType.ManualActivity)
                    };

                    Domain.Transition transition = new Domain.Transition()
                    {
                        ID = IdGenerator.NewComb().ToString(),
                        DestActID = destActivity.ID,
                        DestActInstID = destActInst.ID,
                        DestActInstName = destActInst.Name,
                        DestActName = destActivity.Name,
                        ProcessInstID = processInstID,
                        ProcessInstName = Context.ProcessInst.Name,
                        SrcActID = srcActivity.ID,
                        SrcActInstID = srcActInst.ID,
                        SrcActInstName = srcActInst.Name,
                        SrcActName = srcActivity.Name,
                        TransTime = createTime
                    };

                    TransControl transControl = new TransControl()
                    {
                        ID = IdGenerator.NewComb().ToString(),
                        DestActID = destActivity.ID,
                        DestActName = destActivity.Name,
                        ProcessInstID = processInstID,
                        SrcActID = srcActivity.ID,
                        SrcActName = srcActivity.Name,
                        TransTime = createTime,
                        TransWeight = 100
                    };

                    //srcActInst.CurrentState = (short)ActivityInstStatus.Compeleted;
                    if (destActivity is ManualActivity)
                    {
                        #region ManualActivityHandler

                        ManualActivity ma = destActivity as ManualActivity;
                        WorkItem wi = new WorkItem()
                        {
                            ID = IdGenerator.NewComb().ToString(),
                            ActionMask = string.Empty,
                            ActionURL = ma.CustomURL.SpecifyURL,
                            ActivityInstID = destActInst.ID,
                            ActivityInstName = destActInst.Name,
                            AllowAgent = (short)(ma.AllowAgent ? 1 : 0),
                            BizState = (short)WorkItemBizStatus.Common,
                            CreateTime = createTime,
                            Creator = WFUtil.User.ID,
                            CreatorName = WFUtil.User.Name,
                            CurrentState = (short)WorkItemStatus.WaitExecute,
                            Description = destActInst.Description,
                            EndTime = WFUtil.MaxDate,
                            Executor = string.Empty,
                            ExecutorName = string.Empty,
                            IsTimeOut = 0,
                            Name = destActInst.Name,
                            Participant = Persistence.GetParticipant(processDefID, destActivity.ID),
                            ProcessID = processDefID,
                            ProcessInstID = processInstID,
                            ProcessInstName = Context.ProcessInst.Name,
                            ProcessName = Context.ProcessDefine.Name,
                            RemindTime = WFUtil.MaxDate,
                            RootProcessInstID = string.Empty,
                            StartTime = createTime,
                            TimeOutTime = WFUtil.MaxDate,
                            Type = destActInst.Type,
                            //ExecuteTime = null,
                        };

                        IList<Participantor> participantors = assignParticipant == null ? ma.Participant.Participantors : new List<Participantor> { assignParticipant() };

                        foreach (var participantor in participantors)
                        {
                            Domain.Participant participant = new Domain.Participant()
                            {
                                ID = IdGenerator.NewComb().ToString(),
                                CreateTime = createTime,
                                DelegateType = (short)DelegateType.Sponsor,
                                Name = participantor.Name,
                                ParticipantID = participantor.ID,
                                ParticipantIndex = participantor.SortOrder,
                                ParticipantType = (short)participantor.ParticipantorType.Cast<ParticipantorType>(ParticipantorType.Person),
                                PartiInType = (short)PartiInType.Exe,
                                WorkItemID = wi.ID,
                                WorkItemState = (short)wi.CurrentState
                            };

                            Persistence.Repository.SaveOrUpdate(participant);
                        }

                        Persistence.Repository.SaveOrUpdate(wi);

                        #endregion
                    }
                    else if (destActivity is AutoActivity)
                    {
                        if (!HandlerAutoActivity(processDefID, srcActivity, destActivity, destActInst))
                            destActInst.CurrentState = (short)ActivityInstStatus.Suspended;
                    }

                    srcActInst.CurrentState = (short)ActivityInstStatus.Compeleted;
                    Persistence.Repository.SaveOrUpdate(srcActInst);
                    Persistence.Repository.SaveOrUpdate(destActInst);
                    Persistence.Repository.SaveOrUpdate(transition);
                    Persistence.Repository.SaveOrUpdate(transControl);
                }
            });
        }