Error Help - uBAQ - This platform does not support distributed transactions

Could anyone assist as to why I would get this kind of error with the below code? I am performing serial matching, and I use this exact same code in another process that creates serials and matches them (upper and lower parts). In this case, we have a upper level part I am attempting to match. I manually matched a serial, traced, and verified that the dataset from my code matches what I got from the trace. So… I am very much lost, any help would be greatly appreciated :slight_smile:

Error:

Serial Number Match failed:
--------------------------------
Exception:The underlying provider failed on EnlistTransaction.System.PlatformNotSupportedException: This platform does not support distributed transactions.
   at System.Transactions.Distributed.DistributedTransactionManager.CreateTransaction(TransactionOptions options)
   at System.Transactions.TransactionStatePromoted.EnterState(InternalTransaction tx)
   at System.Transactions.EnlistableStates.Promote(InternalTransaction tx)
   at System.Transactions.Transaction.Promote()
   at System.Transactions.TransactionInterop.ConvertToDistributedTransaction(Transaction transaction)
   at System.Transactions.TransactionInterop.GetExportCookie(Transaction transaction, Byte[] whereabouts)
   at System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction transaction, Byte[] whereAbouts)
   at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnection.EnlistTransaction(Transaction transaction)
   at System.Data.SqlClient.SqlConnection.EnlistTransaction(Transaction transaction)
   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action`2 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
   at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.EnlistTransaction(DbConnection connection, EnlistTransactionInterceptionContext interceptionContext)
   at System.Data.Entity.Core.EntityClient.EntityConnection.EnlistTransaction(Transaction transaction)

Code:

// Support Functions
Func<string, object, bool> debugMsg = (title, dataObj) =>
{
    string jsonTxt = JsonConvert.SerializeObject(dataObj);
    string jsonMessage = string.Format("{0}: {1}{2}", title, Environment.NewLine, jsonTxt);
    this.PublishInfoMessage(jsonMessage, Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"UBAQ", "Advanced");
    return true;
};

Func<string, bool> showMsg = (message) =>
{
    this.PublishInfoMessage(message, Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"UBAQ", "Advanced");
    return true;
};

// Common variables
var currPlant = callContextClient.CurrentPlant;
var currCompany = callContextClient.CurrentCompany;

// Get the params the BAQ was called with
var jobNum = executionParams.ExecutionParameter.Where(m => m.ParameterID == "sJobNum").Select(m => m.ParameterValue).FirstOrDefault();
var assemblySeqStr = executionParams.ExecutionParameter.Where(m => m.ParameterID == "sAssemblySeq").Select(m => m.ParameterValue).FirstOrDefault();
var mtlSeqStr = executionParams.ExecutionParameter.Where(m => m.ParameterID == "sMtlSeq").Select(m => m.ParameterValue).FirstOrDefault();

// Setup our service calls
var serialMatchingSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.SerialMatchingSvcContract>(Db);

if (!string.IsNullOrEmpty(jobNum) && !string.IsNullOrEmpty(assemblySeqStr) && !string.IsNullOrEmpty(mtlSeqStr))
{
  /***************************************************************
   *                  Validations & Data Setup
   ***************************************************************/
   
  // Setup our two int type params
  int assemblySeq = 0;
  int mtlSeq = 0;
  int.TryParse(assemblySeqStr, out assemblySeq);
  int.TryParse(mtlSeqStr, out mtlSeq);
  
  // Ensure we have a JobAsmbl record (aka they saved the Issue Material form)
  var jobAsmblRec = Db.JobAsmbl.Where(m => m.Company == currCompany && m.Plant == currPlant && m.JobNum == jobNum && m.AssemblySeq == assemblySeq).ToList();
  if (!jobAsmblRec.Any())
  {
    string msgTxt = string.Format("ERROR retrieving Job Assembly information");
    showMsg(msgTxt);
    return;
  }
  var jobAsmbl = jobAsmblRec.FirstOrDefault();
  
  // Get the upper level part from JobHead
  string upperlvlPart = Db.JobHead.Where(m => m.Company == currCompany && m.Plant == currPlant && m.JobNum == jobNum)
                                  .Select(m => m.PartNum).First();
  string cfmPart = Db.JobMtl.Where(m => m.Company == currCompany && m.Plant == currPlant && m.JobNum == jobNum)
                              .Select(m => m.PartNum).FirstOrDefault();
  
  // Ensure we have a CFM part, and the logic above didn't pull the same part# twice
  if (string.IsNullOrEmpty(cfmPart) || (cfmPart == upperlvlPart))
  {
    string msgTxt = string.Format("ERROR retrieving the Upper level part and CFM part");
    showMsg(msgTxt);
    return;
  }
  
  // Get our Serial Number prefix for the upper level part
  var snPrefix = Db.PartPlant.Where(m => m.Company == currCompany && m.Plant == currPlant && m.PartNum == upperlvlPart)
                             .Select(m => m.SNPrefix).First();
  
  // Get available WIP serials for our CFM part in SerialNo
  var cfmSerialNumbers = Db.SerialNo.Where(m => m.Company == currCompany && m.PartNum == cfmPart && m.JobNum == jobNum && m.AssemblySeq == assemblySeq && m.MtlSeq == mtlSeq && m.SNStatus == "WIP");
  
  /***************************************************************
   *                Serial Number Matching
   ***************************************************************/

  // Loop through our serials and perform matching
  bool hadError = false;
  List<string> matchedSerials = new List<string>();
  foreach (var serialNum in cfmSerialNumbers)
  {
    var serialNumber = serialNum.SerialNumber;
    var partNum = serialNum.PartNum;
    string opRevMsg;
    string opnoBOMMsg;
    // Append the prefix to the serial number to setup our upper level part serial number
    var uperLvlPartSerial = string.Format("{0}{1}", snPrefix, serialNumber);
    
    var serialMatchingTS = serialMatchingSvc.ChangeSerialNum(uperLvlPartSerial, upperlvlPart, String.Empty, jobNum, assemblySeq, out opRevMsg, out opnoBOMMsg);  
    if (serialMatchingTS != null)
    {
      serialMatchingTS.SerialMatchHdr[0].RowMod = "U";
      serialMatchingTS.SerialMatchAsmbl[0].RowMod = "U";
      serialMatchingSvc.GetAvailableToMatch("mtl", ref serialMatchingTS);
      
      Erp.Tablesets.AvailToMatchTable smAvailToMatchTS = serialMatchingTS.AvailToMatch;
      Erp.Tablesets.SerialMatchMtlTable smMtlTS = serialMatchingTS.SerialMatchMtl;
           
      // Loop through each available to match row in our tableset
      foreach (Erp.Tablesets.AvailToMatchRow arow in smAvailToMatchTS)
      {
        if (arow.SerialNumber == serialNumber && arow.PartNum == cfmPart)
        {
          // Set the matched and selected
          arow.Matched = true;  
          arow.Selected = true;
          
          // loop through the match material rows
          foreach (Erp.Tablesets.SerialMatchMtlRow rowMtl in smMtlTS)
          {
            rowMtl.MtlSerialNo = arow.SerialNumber;
            matchedSerials.Add(string.Format("{0} <--> {1}", rowMtl.MtlSerialNo, rowMtl.TopSerialNum));
            break;
          }
          break;
        }
      }
      
      // Now run the match update
      try
      {
        serialMatchingSvc.UpdateSMMtl("J", ref serialMatchingTS);
      }
      catch (Exception ex)
      {
        string errTxt = string.Format("Serial Number Match failed for {0}:{1}--------------------------------{2}Exception:{3}{4}", 
          uperLvlPartSerial, Environment.NewLine, Environment.NewLine, ex.Message, ex.InnerException);
        hadError = true;
        showMsg(errTxt);
      }
    }
  }
  // Display a matching status to the user
  string finalMsgHeader = "Match CFM Serials process has completed";
  if (hadError) {
    finalMsgHeader = "Match CFM Serials process failed, see below";
  }
  string statHdr = string.Format("Job: {0}{1}Assembly Seq# {2}{3}Mtl Seq# {4}{5}CFM Part: {6}{7}Upper Level Part: {8}{9}",
    jobNum, Environment.NewLine, assemblySeqStr, Environment.NewLine, mtlSeqStr, Environment.NewLine, cfmPart, Environment.NewLine, upperlvlPart, Environment.NewLine);
  string matchStat = string.Join(Environment.NewLine, matchedSerials);
  string FinalMsgTxt = string.Format("{5}:{0}--------------------------------{1}{2}{3}{4}",
    Environment.NewLine, Environment.NewLine, statHdr, Environment.NewLine, matchStat, finalMsgHeader);
  showMsg(FinalMsgTxt);
}

If you are in a function, check the requires transaction checkbox.

If you are not, wrap the relevant part of the code in a transaction scope.


using(var txScope = Ice.IceContext.CreateDefaultTransactionScope())
{
    //code 
    //Edit:
    txScope.Complete();
}

1 Like

Thank you! I gave that a try, wrapped the loop that’s doing the matching (see code below), and the error didn’t occur, but the match didn’t process either. Nor did I get any errors:

using(var txScope = Ice.IceContext.CreateDefaultTransactionScope())
  {
    foreach (var serialNum in cfmSerialNumbers)
    {
      var serialNumber = serialNum.SerialNumber;
      var partNum = serialNum.PartNum;
      string opRevMsg;
      string opnoBOMMsg;
      // Append the prefix to the serial number to setup our upper level part serial number
      var uperLvlPartSerial = string.Format("{0}{1}", snPrefix, serialNumber);
      
      var serialMatchingTS = serialMatchingSvc.ChangeSerialNum(uperLvlPartSerial, upperlvlPart, String.Empty, jobNum, assemblySeq, out opRevMsg, out opnoBOMMsg);  
      if (serialMatchingTS != null)
      {
        serialMatchingTS.SerialMatchHdr[0].RowMod = "U";
        serialMatchingTS.SerialMatchAsmbl[0].RowMod = "U";
        serialMatchingSvc.GetAvailableToMatch("mtl", ref serialMatchingTS);
        
        Erp.Tablesets.AvailToMatchTable smAvailToMatchTS = serialMatchingTS.AvailToMatch;
        Erp.Tablesets.SerialMatchMtlTable smMtlTS = serialMatchingTS.SerialMatchMtl;
             
        // Loop through each available to match row in our tableset
        foreach (Erp.Tablesets.AvailToMatchRow arow in smAvailToMatchTS)
        {
          if (arow.SerialNumber == serialNumber && arow.PartNum == cfmPart)
          {
            // Set the matched and selected
            arow.Matched = true;  
            arow.Selected = true;
            
            // loop through the match material rows
            foreach (Erp.Tablesets.SerialMatchMtlRow rowMtl in smMtlTS)
            {
              rowMtl.MtlSerialNo = arow.SerialNumber;
              matchedSerials.Add(string.Format("{0} <--> {1}", rowMtl.MtlSerialNo, rowMtl.TopSerialNum));
              break;
            }
            break;
          }
        }
        
        // Now run the match update
        try
        {
          serialMatchingSvc.UpdateSMMtl("J", ref serialMatchingTS);
        }
        catch (Exception ex)
        {
          string errTxt = string.Format("Serial Number Match failed for {0}:{1}--------------------------------{2}Exception:{3}{4}", 
            uperLvlPartSerial, Environment.NewLine, Environment.NewLine, ex.Message, ex.InnerException);
          hadError = true;
          showMsg(errTxt);
        }
      }
    }
  }

Nevermind! I had to do .Complete for the transaction, thank you sir!!

Edit: Nevermind…

Sweet.

Sorry, I was on a phone, forgot that part.

1 Like

Hey Rob,

How were you able to find the relevant part of your code that belonged within the transaction scope? I am having a hard time figuring this out. I tried just wrapping the whole thing and it told me to add a reference to assembly System.Transactions.Local (I am unable to find it to add to the assemblies).

image

Adding my error message in case it helps:

System Information

==================

AppServer Connection:
Form Name: Business Activity Query Designer
Customization Name:
Menu ID:
Software Version: 4.2.300.0

============

Server Side Exception

BPM runtime caught an unexpected exception of ‘EntityException’ type.
See more info in the Inner Exception section of Exception Details.

Exception caught in: Epicor.ServiceModel

Error Detail

============

##!Correlation ID:##! f303df26-6649-4ce3-970c-19d5198a4ed9
##!Description:##! BPM runtime caught an unexpected exception of ‘EntityException’ type.
See more info in the Inner Exception section of Exception Details.
##!Inner Exception:##! This platform does not support distributed transactions.
##!Program:##! EntityFramework.dll
##!Method:##! EnlistTransaction
##!Original Exception Type:##! EntityException
##!Framework Method:##! b__3
##!Framework Line Number:##! 1201
##!Framework Column Number:##! 35
##!Framework Source:##! b__3 at offset 20498744 in file:line:column C:_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.System\Data\DBExpressionCompiler.Generated.cs:1201:35

##!Server Trace Stack:##! at System.Data.Entity.Core.EntityClient.EntityConnection.EnlistTransaction(Transaction transaction)
at System.Data.Entity.Core.Objects.ObjectContext.EnsureContextIsEnlistedInCurrentTransaction[T](Transaction currentTransaction, Func1 openConnection, T defaultValue) at System.Data.Entity.Core.Objects.ObjectContext.EnsureConnection(Boolean shouldMonitorTransactions) at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectQuery1.<>c__DisplayClass41_0.<GetResults>b__0() at System.Data.Entity.Core.Objects.ObjectQuery1.<System.Collections.Generic.IEnumerable.GetEnumerator>b__31_0()
at System.Data.Entity.Internal.LazyEnumerator1.MoveNext() at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable1 source, Boolean& found)
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1 source) at System.Data.Entity.Core.Objects.CompiledQuery.ExecuteQuery[TResult](ObjectContext context, Object[] parameterValues) at Epicor.Data.DBExpressionCompiler.<>c__DisplayClass55_13.b__3(TContext c, Func3 query) in C:\_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.System\Data\DBExpressionCompiler.Generated.cs:line 1201 at Epicor.Data.DBExpressionCompiler.GetResult[TDataContext,TQuery,TResult](Func3 executeQuery, Cache cacheSetting, TDataContext dataContext, TQuery query) in C:_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.System\Data\DBExpressionCompiler.cs:line 449
at Epicor.Data.DBExpressionCompiler.InvokeSingle[TDataContext,TQuery,TResult](Expression expression, Cache currentCacheSetting, Boolean cacheQuery, TDataContext dataContext, Func2 getDataCacheKey, Func2 compileQuery, Func3 executeQuery) in C:\_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.System\Data\DBExpressionCompiler.cs:line 310 at Epicor.Data.DBExpressionCompiler.<>c__DisplayClass55_03.b__0(TContext context, TArg1 arg1) in C:_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.System\Data\DBExpressionCompiler.Generated.cs:line 0
at Erp.Services.BO.LaborSvc.LaborDtlBeforeBI() in C:_releases\ERP\ERP11.2.300.0\Source\Server\Services\BO\Labor\Labor.cs:line 9437
at Ice.Services.Trace.TablesetProfilingCollector.DoRowEventTrace(String tableName, String methodName, Int32 rowCount, Action action) in C:_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.Ice\Services\TablesetProfilingCollector.cs:line 116
at Ice.TablesetBound3.UpdateRow(IceDataContext dataContext, Int32 tableNum, IIceTable table, IceRow updatedRow, IceRow originalRow, IColumnUncensor uncensor, TablesetProfilingCollector parentTraceCollector) in C:\_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.Ice\Services\TablesetBound.cs:line 1268 at Ice.TablesetBound3.WriteTable(IceDataContext dataContext, Int32 tableIndex, IIceTable table, TablesetProfilingCollector parentTraceCollector) in C:_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.Ice\Services\TablesetBound.cs:line 954
at Ice.TablesetBound3.InnerUpdate[TUpdater](IceDataContext dataContext, TFullTableset tableset) in C:\_releases\ICE\ICE4.2.300.10\Source\Server\Framework\Epicor.Ice\Services\TablesetBound.cs:line 874 at Erp.Services.BO.LaborSvc.Update(LaborTableset& ds) in C:\_releases\ERP\ERP11.2.300.0\Source\Server\Services\BO\Labor\Labor.Designer.cs:line 2617 at Erp.Services.BO.LaborSvcFacade.Update(LaborTableset& ds) in C:\_releases\ERP\ERP11.2.300.0\Source\Server\Services\BO\Labor\LaborSvcFacade.cs:line 5928 at Epicor.Customization.Bpm.Ubaq.GetListPostProcessingDirective_FirstShiftAutoClockOut_2ED75D0BC4684026B2835D74FC833043.A001_CustomCodeAction() at Epicor.Customization.Bpm.Ubaq.GetListPostProcessingDirective_FirstShiftAutoClockOut_2ED75D0BC4684026B2835D74FC833043.ExecuteCore(Int32 step) at Epicor.Customization.Bpm.DirectiveBase2.Execute() in C:_releases\ICE\ICE4.2.300.10\Source\Server\Internal\Lib\Epicor.Customization.Bpm\DirectiveBase.Generic.cs:line 330
at Epicor.Customization.Bpm.DirectiveBase`2.Execute(TParam parameters) in C:_releases\ICE\ICE4.2.300.10\Source\Server\Internal\Lib\Epicor.Customization.Bpm\DirectiveBase.Generic.cs:line 222

Inner Trace:
This platform does not support distributed transactions.
: at System.Transactions.Distributed.DistributedTransactionManager.CreateTransaction(TransactionOptions options)
at System.Transactions.TransactionStatePromoted.EnterState(InternalTransaction tx)
at System.Transactions.EnlistableStates.Promote(InternalTransaction tx)
at System.Transactions.Transaction.Promote()
at System.Transactions.TransactionInterop.ConvertToDistributedTransaction(Transaction transaction)
at System.Transactions.TransactionInterop.GetExportCookie(Transaction transaction, Byte whereabouts)
at System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction transaction, Byte whereAbouts)
at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
at System.Data.SqlClient.SqlInternalConnection.EnlistTransaction(Transaction transaction)
at System.Data.SqlClient.SqlConnection.EnlistTransaction(Transaction transaction)
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action2 operation, TInterceptionContext interceptionContext, Action3 executing, Action3 executed)
at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.EnlistTransaction(DbConnection connection, EnlistTransactionInterceptionContext interceptionContext)
at System.Data.Entity.Core.EntityClient.EntityConnection.EnlistTransaction(Transaction transaction)

Client Stack Trace

==================
at Ice.Cloud.ProxyBase1.CallWithCommunicationFailureRetry(String methodName, ProxyValuesIn valuesIn, ProxyValuesOut valuesOut, RestRpcValueSerializer serializer) at Ice.Cloud.ProxyBase1.CallWithMultistepBpmHandling(String methodName, ProxyValuesIn valuesIn, ProxyValuesOut valuesOut, Boolean useSparseCopy)
at Ice.Cloud.ProxyBase1.Call(String methodName, ProxyValuesIn valuesIn, ProxyValuesOut valuesOut, Boolean useSparseCopy) at Ice.Proxy.BO.DynamicQueryImpl.GetList(DynamicQueryDataSet queryDS, QueryExecutionDataSet executionParams, Int32 pageSize, Int32 absolutePage, Boolean& hasMorePage) at Ice.Adapters.DynamicQueryAdapter.<>c__DisplayClass45_0.<GetList>b__0(DataSet datasetToSend) at Ice.Adapters.DynamicQueryAdapter.ProcessUbaqMethod(String methodName, DataSet updatedDS, Func2 methodExecutor, Boolean refreshQueryResultsDataset)
at Ice.Adapters.DynamicQueryAdapter.GetList(DynamicQueryDataSet queryDS, QueryExecutionDataSet execParams, Int32 pageSize, Int32 absolutePage, Boolean& hasMorePage)
at Ice.UI.App.BAQDesignerEntry.BAQTransaction.TestCallListBckg()
at Ice.UI.App.BAQDesignerEntry.BAQTransaction.<>c__DisplayClass220_0.b__0()
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()

Inner Exception

===============
The underlying provider failed on EnlistTransaction.

You’ll need to have the .Net 6 SDK installed.

If you do that, and are getting missing dependencies like above, check this thread:

You probably have an empty folder there it’s referencing.

no, the error is different. SDK should be enough Does .NET 6 SDK need to be installed on all users workstations?

1 Like

I installed the latest SDK and that did solve the problem I was having in my initial reply. Thank you! Now when I try and run my BPM I am getting the same error I was before I implemented @klincecum’s recommended fix here:

I am not using functions but am not sure what Kevin means by

If you are not [in a function], wrap the relevant part of the code in a transaction scope.

Am I missing something here? I can’t find any reference to my code in the error message I posted above.

If wrapping your entire code in the transaction scope didn’t fix it, then post your code so we can look at it.

I am now getting the same error regardless of if I use your CreateDefaultTransactionScope fix. Here is the code I have currently:

string company = Session.CompanyID;

var empBasic = ServiceRenderer.GetService<Erp.Contracts.EmpBasicSvcContract>(Db);
var labor = ServiceRenderer.GetService<Erp.Contracts.LaborSvcContract>(Db);

var laborHeds = Db.LaborHed.Where(lh =lh.Company == company
                                     && lh.ActiveTrans);
List<string> empIds = new List<string>();

foreach(var laborHed in laborHeds) {
  Erp.Tablesets.LaborTableset laborTs = labor.GetByID(laborHed.LaborHedSeq);
  
  int updates = 0;
  
  foreach(var laborDtl in laborTs.LaborDtl.Where(ld =ld.ActiveTrans)) {
    laborDtl.EndActivity = true;
    laborDtl.RowMod = "U";
    updates++;
  }
     
  if (updates > 0) {
    labor.Update(ref laborTs);
  }
  

  var empIdsOnShift1 = Db.LaborDtl.Where(ld =ld.ActiveTrans && ld.Shift == 1)
                      .Select(ld =ld.EmployeeNum)
                      .ToList();
  empIds.AddRange(empIdsOnShift1);
}


foreach(string empId in empIds) {
  string e = empId;
  empBasic.ClockOut(ref e);
}

Where is Db coming from? Do you create separate context? The distributed transaction error happens when 1 transaction uses 2 different connections in 2 contexts

He’s in a UBAQ.

He’s left an open cursor to the db there, could it be interfering?

Yes, UBAQ @Olga. I’m not a great developer, so learning a lot.

I think I see it.
Edit: Nevermind

Try adding .ToList() to bring it back and close the cursor. May or may not make a difference.

1 Like

I’m looking at my code here that does basically the same thing.

I don’t think you can just set .EndActivity = true and update.
I think it does other stuff in the background.

try:

  foreach(var laborDtl in laborTs.LaborDtl.Where(ld =ld.ActiveTrans)) {
    //laborDtl.EndActivity = true;
    laborDtl.RowMod = "U";
    labor.EndActivity(ref laborDtl);
    updates++;
  }

However, I seem to recall maybe running into this same thing, and in my code, I do it like this, one at a time. I’m thinking there was a reason, but I can’t recall completely.

         // End Activities
          foreach (var dtl in laborData.LaborDtl)
          {
              if (dtl.ActiveTrans)
              {
                dtl.RowMod = "U";    
                labor.EndActivity(ref laborData);
                labor.Update(ref laborData);
              }
            }
2 Likes

also start each line with using(var …) { …

Actually you should post your own complete error stack, so we see where the error happens