Tried that… no change.
Try to wrap it in this using statement?
using (System.Transactions.TransactionScope txScope = IceDataContext.CreateDefaultTransactionScope())
{
}
I am invoking the business which carries its own transaction scope when it reaches back into the server.
From what I understand when it comes to ServiceRenderer. I am sure Bart will correct me, might be off a bit.
When you use Ice.Assemblies.ServiceRenderer.GetService() you are creating a Assembly Instance without any args so i assume it will create its own context instance / transaction.
When you use Ice.Assemblies.ServiceRenderer.GetService(Db) you are calling GetService(IceDataContext context, bool ignoreFacade = false) which does an CreateInstance and passes the Db Context as an argument to the Assembly. Which is returned to you.
When you use Ice.Assemblies.ServiceRenderer.GetService(Db, true) you are also setting the ignoreFacade to true… What is a Facade in Epicor? Well if you use the ICE SDK and you create your own Business Objects you always create a SvcFacade.cs file which contains the required code for interacting with BPM… So by setting ignoreFacade to true you are basically saying… Do Not Trigger the “Update” BPM… perhaps you want it, but if you are in the Update already you would cause a loop.
I am wondering if it helps to pass through the Db Context. Perhaps there is a issue in how ServiceRenderer instantiates the Transaction, perhaps it does not pass the Client Context.
Seems a bit odd.
Can you include the detail from the error so we can see the stack trace.
Also can you recreate this in Training DB?
It is as if you are getting back changed data from the ChangeJobHeadJobReleased method.
Have you attached a debugger and compared what is being passed into update, or tried without the ChangeJob method in the chain?
@Edge
Full stack trace below, BPM attached E10Test.bpm (11.8 KB) runs on ABC Code -> Get New only fails if Prevent Changes is Checked in Company Config -> Production -> Change Engineered Jobs
I haven’t tried it in the Training DB, but I will
Business Layer Exception
Update not allowed, Engineered and Prevent Changes.
Exception caught in: Epicor.ServiceModel
Error Detail
============
Description: Update not allowed, Engineered and Prevent Changes.
Program: Erp.Services.BO.JobEntry.dll
Method: valPreventChange
Line Number: 5954
Column Number: 29
Table: JobAsmbl
Server Trace Stack: at Erp.Services.BO.JobEntrySvc.valPreventChange() in C:\_Releases\ERP\UD10.1.500.8\Source\Server\Services\BO\JobEntry\JobEntry.cs:line 5954
at Erp.Services.BO.JobEntrySvc.BeforeUpdate() in C:\_Releases\ERP\UD10.1.500.8\Source\Server\Services\BO\JobEntry\JobEntry.cs:line 5965
at Erp.Services.BO.JobEntrySvc.OnTablesetEvent(DatasetEventType type) in C:\_Releases\ERP\UD10.1.500.8\Source\Server\Services\BO\JobEntry\JobEntry.Designer.cs:line 619
at Ice.Services.Trace.TablesetProfilingCollector.DoTablesetEventTrace(String tablesetName, String methodName, Action action) in C:\_Releases\ICE\3.1.500.8\Source\Framework\Epicor.Ice\Services\TablesetProfilingCollector.cs:line 200
at Ice.TablesetBound`3.InnerUpdate(IceDataContext dataContext, TFullTableset tableset) in C:\_Releases\ICE\3.1.500.8\Source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 794
at Erp.Services.BO.JobEntrySvc.Update(JobEntryTableset& ds) in C:\_Releases\ERP\UD10.1.500.8\Source\Server\Services\BO\JobEntry\JobEntry.Designer.cs:line 7392
at Erp.Services.BO.JobEntrySvcFacade.Update(JobEntryTableset& ds) in C:\_Releases\ERP\UD10.1.500.8\Source\Server\Services\BO\JobEntry\JobEntrySvcFacade.cs:line 4043
at Epicor.Customization.Bpm.BO1A649256125F45B2A3A14D0B240477F1.GetNewABCCodePreProcessingDirective_TEST_E93C55B5ED684B728BF4D2BC44B8F28A.A001_CustomCodeAction()
at Epicor.Customization.Bpm.BO1A649256125F45B2A3A14D0B240477F1.GetNewABCCodePreProcessingDirective_TEST_E93C55B5ED684B728BF4D2BC44B8F28A.ExecuteCore()
at Epicor.Customization.Bpm.DirectiveBase`3.Execute(TParam parameters) in c:\_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\DirectiveBase.Generic.cs:line 160
at Epicor.Customization.Bpm.MethodCustomizationBase2`3.<>c__DisplayClass20_0.<RunDirectives>b__3(MethodDirectiveBase`3 dir) in c:\_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\MethodCustomizationBase2.cs:line 151
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
at Epicor.Customization.Bpm.MethodCustomizationBase2`3.RunDirectives(TParam parameters) in c:\_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\MethodCustomizationBase2.cs:line 153
at Epicor.Customization.Bpm.CustomizationBase2`3.Execute(TParam parameters) in c:\_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\CustomizationBase2.cs:line 77
at Epicor.Customization.Bpm.BO1A649256125F45B2A3A14D0B240477F1.ABCCodeSvcCustomization.GetNewABCCode(ABCCodeTableset& ds)
at Erp.Services.BO.ABCCodeSvcFacade.GetNewABCCode(ABCCodeTableset& ds) in c:\_Releases\ERP\RL10.1.500\Source\Server\Services\BO\ABCCode\ABCCodeSvcFacade.cs:line 60
at SyncInvokeGetNewABCCode(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at Epicor.Hosting.OperationBoundInvoker.InnerInvoke(Object instance, Func`2 func) in C:\_Releases\ICE\3.1.500.8\Source\Framework\Epicor.System\Hosting\OperationBoundInvoker.cs:line 59
at Epicor.Hosting.OperationBoundInvoker.Invoke(Object instance, Func`2 func) in C:\_Releases\ICE\3.1.500.8\Source\Framework\Epicor.System\Hosting\OperationBoundInvoker.cs:line 28
at Epicor.Hosting.Wcf.EpiOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) in C:\_Releases\ICE\3.1.500.8\Source\Framework\Epicor.System\Hosting\Wcf\EpiOperationInvoker.cs:line 23
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
at System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.SecurityChannelListener`1.ReceiveItemAndVerifySecurityAsyncResult`2.InnerTryReceiveCompletedCallback(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.TransportDuplexSessionChannel.TryReceiveAsyncResult.OnReceive(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.SynchronizedMessageSource.ReceiveAsyncResult.OnReceiveComplete(Object state)
at System.ServiceModel.Channels.SessionConnectionReader.OnAsyncReadComplete(Object state)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Security._SslStream.ProcessFrameBody(Int32 readBytes, Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security._SslStream.ReadFrameCallback(AsyncProtocolRequest asyncRequest)
at System.Net.AsyncProtocolRequest.CompleteRequest(Int32 result)
at System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(Int32 bytes)
at System.Net.FixedSizeReader.ReadCallback(IAsyncResult transportResult)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.ConnectionStream.IOAsyncResult.OnAsyncIOComplete(Object state)
at System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(SocketAsyncEventArgs e)
at System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
at System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
Client Stack Trace
==================
at Epicor.ServiceModel.Channels.ImplBase`1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets)
at Erp.Proxy.BO.ABCCodeImpl.GetNewABCCode(ABCCodeDataSet ds)
at Erp.Adapters.ABCCodeAdapter.GetNewAbcCode()
at Erp.UI.App.AbcCodeEntry.Transaction.GetNew()
at Ice.Lib.Framework.EpiSingleViewTransaction.Ice.Lib.Framework.IEpiAdapterLink.GetNew()
at Ice.Lib.Framework.EpiViewUtils.OnGetNew(EpiTransaction trans, EpiDataView view, IEpiAdapterLink link, Boolean displayExceptions)
BTW I tried without the ChangeMethod just now, same result.
Tried it in Education DB
Company “Epicor Education”
Job: 2031
BPM Attached / Modified for Job 2031 in Training DB, Same Result
E10TestEducation.bpm (11.3 KB)
You need to set the Prevent Changes in the Company Configuration (below)
Full Stack Trace for Training DB Below (though it should be the same as above)
Business Layer Exception
Update not allowed, Engineered and Prevent Changes.
Exception caught in: Epicor.ServiceModel
Error Detail
============
Description: Update not allowed, Engineered and Prevent Changes.
Program: Erp.Services.BO.JobEntry.dll
Method: valPreventChange
Line Number: 5954
Column Number: 29
Table: JobAsmbl
Server Trace Stack: at Erp.Services.BO.JobEntrySvc.valPreventChange() in C:\_Releases\ERP\UD10.1.500.7\Source\Server\Services\BO\JobEntry\JobEntry.cs:line 5954
at Erp.Services.BO.JobEntrySvc.BeforeUpdate() in C:\_Releases\ERP\UD10.1.500.7\Source\Server\Services\BO\JobEntry\JobEntry.cs:line 5963
at Erp.Services.BO.JobEntrySvc.OnTablesetEvent(DatasetEventType type) in C:\_Releases\ERP\UD10.1.500.7\Source\Server\Services\BO\JobEntry\JobEntry.Designer.cs:line 619
at Ice.Services.Trace.TablesetProfilingCollector.DoTablesetEventTrace(String tablesetName, String methodName, Action action) in C:\_Releases\ICE\3.1.500.7\Source\Framework\Epicor.Ice\Services\TablesetProfilingCollector.cs:line 200
at Ice.TablesetBound`3.InnerUpdate(IceDataContext dataContext, TFullTableset tableset) in C:\_Releases\ICE\3.1.500.7\Source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 794
at Erp.Services.BO.JobEntrySvc.Update(JobEntryTableset& ds) in C:\_Releases\ERP\UD10.1.500.7\Source\Server\Services\BO\JobEntry\JobEntry.Designer.cs:line 7392
at Erp.Services.BO.JobEntrySvcFacade.Update(JobEntryTableset& ds) in C:\_Releases\ERP\UD10.1.500.7\Source\Server\Services\BO\JobEntry\JobEntrySvcFacade.cs:line 4043
at Epicor.Customization.Bpm.BO9AF352B197AD49158C3BF8C381E20873.GetNewABCCodePreProcessingDirective_TEST_BAD_BPM_E93C55B5ED684B728BF4D2BC44B8F28A.A001_CustomCodeAction()
at Epicor.Customization.Bpm.BO9AF352B197AD49158C3BF8C381E20873.GetNewABCCodePreProcessingDirective_TEST_BAD_BPM_E93C55B5ED684B728BF4D2BC44B8F28A.ExecuteCore()
at Epicor.Customization.Bpm.DirectiveBase`3.Execute(TParam parameters) in c:\_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\DirectiveBase.Generic.cs:line 160
at Epicor.Customization.Bpm.MethodCustomizationBase2`3.<>c__DisplayClass20_0.<RunDirectives>b__3(MethodDirectiveBase`3 dir) in c:\_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\MethodCustomizationBase2.cs:line 151
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
at Epicor.Customization.Bpm.MethodCustomizationBase2`3.RunDirectives(TParam parameters) in c:\_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\MethodCustomizationBase2.cs:line 153
at Epicor.Customization.Bpm.CustomizationBase2`3.Execute(TParam parameters) in c:\_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\CustomizationBase2.cs:line 77
at Epicor.Customization.Bpm.BO9AF352B197AD49158C3BF8C381E20873.ABCCodeSvcCustomization.GetNewABCCode(ABCCodeTableset& ds)
at Erp.Services.BO.ABCCodeSvcFacade.GetNewABCCode(ABCCodeTableset& ds) in c:\_Releases\ERP\RL10.1.500\Source\Server\Services\BO\ABCCode\ABCCodeSvcFacade.cs:line 60
at SyncInvokeGetNewABCCode(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at Epicor.Hosting.OperationBoundInvoker.InnerInvoke(Object instance, Func`2 func) in C:\_Releases\ICE\3.1.500.7\Source\Framework\Epicor.System\Hosting\OperationBoundInvoker.cs:line 59
at Epicor.Hosting.OperationBoundInvoker.Invoke(Object instance, Func`2 func) in C:\_Releases\ICE\3.1.500.7\Source\Framework\Epicor.System\Hosting\OperationBoundInvoker.cs:line 28
at Epicor.Hosting.Wcf.EpiOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) in C:\_Releases\ICE\3.1.500.7\Source\Framework\Epicor.System\Hosting\Wcf\EpiOperationInvoker.cs:line 23
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
at System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.SecurityChannelListener`1.ReceiveItemAndVerifySecurityAsyncResult`2.InnerTryReceiveCompletedCallback(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.TransportDuplexSessionChannel.TryReceiveAsyncResult.OnReceive(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.SynchronizedMessageSource.ReceiveAsyncResult.OnReceiveComplete(Object state)
at System.ServiceModel.Channels.SessionConnectionReader.OnAsyncReadComplete(Object state)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Security.NegotiateStream.ProcessFrameBody(Int32 readBytes, Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.NegotiateStream.ReadCallback(AsyncProtocolRequest asyncRequest)
at System.Net.AsyncProtocolRequest.CompleteRequest(Int32 result)
at System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(Int32 bytes)
at System.Net.FixedSizeReader.ReadCallback(IAsyncResult transportResult)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.ConnectionStream.IOAsyncResult.OnAsyncIOComplete(Object state)
at System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(SocketAsyncEventArgs e)
at System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
at System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
Client Stack Trace
==================
at Epicor.ServiceModel.Channels.ImplBase`1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets)
at Erp.Proxy.BO.ABCCodeImpl.GetNewABCCode(ABCCodeDataSet ds)
at Erp.Adapters.ABCCodeAdapter.GetNewAbcCode()
at Erp.UI.App.AbcCodeEntry.Transaction.GetNew()
at Ice.Lib.Framework.EpiSingleViewTransaction.Ice.Lib.Framework.IEpiAdapterLink.GetNew()
at Ice.Lib.Framework.EpiViewUtils.OnGetNew(EpiTransaction trans, EpiDataView view, IEpiAdapterLink link, Boolean displayExceptions)
Thanks @Edge
I think that is your delta in the usage.
public static TService GetService(bool ignoreFacade = false) where TService : class
ignoreFacade bypasses BPM firing. By default that is false so no BPM will be fired. (This defaults false so we don’t end up in an endless loop accidentally with a BPM firing itself recursively).
I think you meant the opposite of this, it defaults to ignore=false meaning it will not ignore the facade. I just tried this and by default BPM does fire, if ingorefacade = true then no BPM fires…
Regardless though this isn’t related to the initial issue (I don’t think) of why the code behaves differently from the client side vs the bpm. Any ideas on that?
No clue if both are firing the bpm. I wonder if that logic is doing something with cross services as well. It would take a bit to unravel. Queue up a call if you need it looked into.
I’ve been a little buried in 10.2 efforts in a new role. Don’t have as much free time as previous with the holidays
No I did them independently, no worries I worked around it for now
Thanks!
PS: New Role? DO TELL
I am running into the same problem. Do we know the cause of the problem?
How did you work around this? I can’t seem to get it at all.
I used BeforeImage.
Well, I tried it and no, it still did not care. I solved some of my BO errors, but not the final update. instead I used UpdateExt… Then, it would allow me to delete the record. This was likely the ugliest code/logic I have ever written (there is a lot more in the rest of the requirement and not below) and it still isn’t 100%…
this.CallService<Erp.Contracts.JobEntrySvcContract>(hJob =>{
Erp.Tablesets.JobHeadRow row = new Erp.Tablesets.JobHeadRow(){
Company = CompanyID,
JobNum = oldJobNum,
PartNum = callContextBpmData.Character03,
Plant = callContextClient.CurrentPlant,
JobEngineered = false,
ChangeDescription = "Rename Job to: " + newJobNum,
};
dsOldJobExt.JobHead.Add(row);
dsErrors = hJob.UpdateExt(ref dsOldJobExt, true, true, out errorsOccured);
dsOldJob = hJob.GetByID("oldJobNum");
dsOldJob.JobProd[0].RowMod = "D";
hJob.Update(ref dsOldJob);
hJob.DeleteByID(oldJobNum);
});
I’ve been struggling with this exact same issue to try and automate the closing of maintenance jobs upon the completion of the final op. Except I couldn’t even get a direct call to JobEntry.UpdateExt to work. So I tried my go-to (read: “overly abused”) method of routing things through DynamicQuery and it worked.
The UBAQ this calls also updates via JobEntry.UpdateExt. So I remain at a loss as to how/why this works when all other, better methods failed. However, I’m also at the point were I don’t care either. At the very least, I think I take the for “ugliest solution”.
using (var svc = Ice.Assemblies.ServiceRenderer.GetService<Ice.Contracts.DynamicQuerySvcContract>(Db))
{
var paramRow = new ExecutionParameterRow();
paramRow.ParameterID = "JobNum";
paramRow.ParameterValue = ttLaborDtl[0].JobNum;
paramRow.ValueType = "nvarchar";
qeds.Tables[1].Add(paramRow);
baqds = svc.ExecuteByID("mnt", qeds);
if (baqds.Tables["Results"].Rows.Count > 0)
{
var resultRow = baqds.Tables["Results"].Rows[0];
resultRow["JobHead_JobClosed"] = true;
resultRow["JobHead_ResTopicID1"] = "PASS";
resultRow["JobHead_CommentText"] =
"Automatically closed by " + callContextClient.CurrentUserId;
svc.UpdateByID("mnt", baqds);
}
}
Add me to the list of people that received the error “Update not allowed, Engineered and Prevent Changes.” when modifying JobReleased (and JobEngineered) values.
I had what I thought was functional code performing a simple task, and it did work using WCF BO calls on JobEntry, but stopped working once I converted the code to use the service library for JobEntry (as necessary for BPMs and Functions).
I tried adding the original row into the dataset, but that didn’t work in my case. I tried about a thousand other changes, variations, etc, with no success. I even tried the changes in REST with the exact same results and error. What did work, was to remove all rows from all the tables, except the original and modified rows for JobHead. I accomplished this by creating a new Job Entry dataset (tableset) and copying the two necessary rows into the JobHead table, as shown in the abbreviated code below.
var context = Ice.Services.ContextFactory.CreateContext<ErpContext>();
using (var boJob = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.JobEntrySvcContract>(context, false))
{
//get current dataset;
Erp.Tablesets.JobEntryTableset dsJeTmp = boJob.GetDatasetForTree(jobNum, 0, 0, false, "MFG,PRJ,SRV");
//get the current datarow of interest;
var jeRowTmp = (from fromJe in dsJeTmp.JobHead
select fromJe).FirstOrDefault();
//create new dataset to pass through as parameter;
Erp.Tablesets.JobEntryTableset dsJe = new Erp.Tablesets.JobEntryTableset();
//create copy of original row;
var origRow = dsJe.JobHead.NewRow();
BufferCopy.Copy(jeRowTmp, origRow);
dsJe.JobHead.Add(origRow);
//create second copy of original row to become the modified row;
var jeRow = (Erp.Tablesets.JobHeadRow) dsJe.JobHead.NewRow();
BufferCopy.Copy(jeRowTmp, jeRow);
dsJe.JobHead.Add(jeRow);
//set fields
jeRow.JobReleased = false;
jeRow.RowMod = "U";
//call methods
boJob.ChangeJobHeadJobReleased(ref dsJe);
boJob.Update(ref dsJe);
}
Side note - this same fix applies to the REST call as well. Remove all rows from all tables, except the original and modified rows for JobHead.
Thanks, everyone, for the help on this and the many other areas this community shares its knowledge.
So, I looking at @Chris code, and playing around with what I had already, it seems Update() wants just the header row and gets angry if you have anything in the child tables.
(Running this in a function, for those not sure why my syntax is a bit different from the post above)
this.CallService<Erp.Contracts.JobEntrySvcContract>(svc =>
{
Erp.Tablesets.JobEntryTableset jets = svc.GetByID(job.JobNum);
var emptyJets = new Erp.Tablesets.JobEntryTableset();
//Copy the JobHead row, and only that, to the empty tableset.
var newRow = emptyJets.JobHead.NewRow();
BufferCopy.Copy(jets.JobHead[0], newRow);
emptyJets.JobHead.Add(newRow);
//modify the row
emptyJets.JobHead[0].JobEngineered = false;
emptyJets.JobHead[0].RowMod = "U";
//Let this method do its thing.
svc.ChangeJobHeadJobEngineered(ref emptyJets);
//run the update
svc.Update(ref emptyJets);
});