Data Directive In-Transaction Processing with Other Services

I’m running the Generate Rebate Transaction Process. I have data directive BPM that does some processing using other Services. The data direct works when I add a record via rest or an updatable BAQ but as soon as I run the process, the task errors out with this message:

Program Ice.Services.Lib.RunTask raised an unexpected exception with the following message: RunTask: An error occurred while updating the entries. See the inner exception for details.
Stack Trace:
   at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
   at Ice.IceDataContext.SaveChanges(SaveOptions options) in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Data\IceDataContext.cs:line 356
   at Ice.IceDataContext.SaveChangesIfRowHasBeenChanged[TLinqRow](TLinqRow row) in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Data\IceDataContext.cs:line 543
   at Ice.Triggers.TriggerQueue.RunWriteTriggerInNewLevel(IceDataContext context, LinqRow modifiedRecord, LinqRow originalRecord, Boolean forAddedRow) in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Triggers\TriggerQueue.cs:line 174
   at Ice.Triggers.TriggerQueue.<>c__DisplayClass11_0.<RunWriteTrigger>b__1() in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Triggers\TriggerQueue.cs:line 148
   at Ice.Triggers.TriggerQueue.RunAtNewLevel(Func`1 buildTriggerRunState, Action action) in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Triggers\TriggerQueue.cs:line 501
   at Ice.Triggers.TriggerQueue.RunTriggers(IceDataContext context) in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Triggers\TriggerQueue.cs:line 83
   at Ice.IceDataContext.RunUntilAllTriggersHaveExecuted() in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Data\IceDataContext.cs:line 572
   at Ice.Triggers.TriggerQueue.RunAtNewLevel(Func`1 buildTriggerRunState, Action action) in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Triggers\TriggerQueue.cs:line 501
   at Ice.IceDataContext.Validate[TLinqRow](TLinqRow row) in C:\_Releases\ICE\ICE3.2.200.10\Source\Framework\Epicor.System\Data\IceDataContext.cs:line 329
   at Erp.Internal.AR.GenRebateTran.generateTrans() in C:\_Releases\ERP\UD10.2.200.10\Source\Server\Internal\AR\GenRebateTran\GenRebateTran.cs:line 792
   at Erp.Internal.AR.GenRebateTran.RunProcess(Int64 InstanceTaskNum, String OutputFileName) in C:\_Releases\ERP\UD10.2.200.10\Source\Server\Internal\AR\GenRebateTran\GenRebateTran.cs:line 503
   at Ice.Hosting.TaskCaller.InnerExecuteTask(IceDataContext newContext) in C:\_Releases\ICE\RL3.2.200.0\Source\Framework\Epicor.Ice\Hosting\TaskCaller\TaskCaller.cs:line 98
   at Ice.Hosting.TaskCaller.ExecuteTask() in C:\_Releases\ICE\RL3.2.200.0\Source\Framework\Epicor.Ice\Hosting\TaskCaller\TaskCaller.cs:line 57
   at Ice.Lib.RunTask.BpmFriendlyTaskLauncher.Run(String sessionIdPrefix, IceContext db, Action taskRunner) in C:\_Releases\ICE\ICE3.2.200.10\Source\Server\Services\Lib\RunTask\BpmFriendlyTaskLauncher.cs:line 63
   at Ice.Services.Lib.RunTaskSvc.InnerRunTask(Int64 ipTaskNum, Boolean suppressTransaction) in C:\_Releases\ICE\ICE3.2.200.10\Source\Server\Services\Lib\RunTask\RunTask.cs:line 549
Inner Exception:
The transaction associated with the current connection has completed but has not been disposed.  The transaction must be disposed before the connection can be used to execute SQL statements.
Stack Trace:
   at System.Data.SqlClient.TdsParser.TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
   at System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.Execute(Dictionary`2 identifierValues, List`1 generatedValues)
   at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()

When I’m calling the service, I’m using this pattern:

 using (System.Transactions.TransactionScope txScope = Erp.ErpContext.CreateDefaultTransactionScope())
 {
     using (GLJrnGrpSvcContract jrnGrpService = ServiceRenderer.GetService<GLJrnGrpSvcContract>(Db, false))
      {
           //Do work
      }
      txScope.Complete();
    }

Based of the results of the processing I’m setting a UD field on the RebatTrans record. I want to be able to stop the record from being added if my custom processing fails or has an exception.
I’m not sure what piece I’m missing. Any help would be greatly appreciated!

Apparently my missing piece was the Db.Validate() prior to txtScope.Complete()
so

 using (System.Transactions.TransactionScope txScope = Erp.ErpContext.CreateDefaultTransactionScope())
 {
     using (GLJrnGrpSvcContract jrnGrpService = ServiceRenderer.GetService<GLJrnGrpSvcContract>(Db, false))
      {
           //Do work
      }
      Db.Validate();
      txScope.Complete();
    }
2 Likes