WCF Update of CustCnt throws exception

I have been testing WCF in E10 and have working code against the Customer service, but similar code against the CustCnt service throws and exception. Using a simple test example, I retrieve rows for a customer, look through looking for a last name, update the First Name, set RowMod to “U” and then perform an Update.

var custcnt = new CustCntTableset();
custcnt = cuscntclient.GetRows(out morePages, “CustNum = 5219”, “”, 0, 1);
foreach (CustCntRow cnt in custcnt.CustCnt)
{
    If (cnt.LastName == “VonDerHaar”)
    {
        Cnt.FirstName = “Test”;
        Cnt.RowMod = “U”;
    }
    Custcntclient.Update(ref custcnt);
}

An exception is raised when the Update is attempted:

System.Data.UpdateException: An error occurred while updating the entries. See the inner exception for details. —> System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint ‘PK_CustCnAttr’. Cannot insert duplicate key in object ‘Erp.CustCnAttr’. The duplicate key value is (FCII01, 5219, , 1, ).
The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
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 Epicor.Data.Provider.EpiCommand.ExecuteDbDataReader(CommandBehavior behavior) in c:_Releases\ICE\3.1.400.10\source\Framework\Epicor.System\Data\EpiProvider2\EpiCommand.cs:line 274
at System.Data.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary2 identifierValues, List1 generatedValues)
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
— End of inner exception stack trace —
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at Ice.IceDataContext.SaveChanges(SaveOptions options) in c:_Releases\ICE\3.1.400.10\source\Framework\Epicor.System\Data\IceDataContext.cs:line 328
at Ice.IceDataContext.Validate[TLinqRow](TLinqRow row) in c:_Releases\ICE\3.1.400.10\source\Framework\Epicor.System\Data\IceDataContext.cs:line 295
at Erp.Services.BO.CustCntSvc.updateAttributes() in c:_Releases\ERP\RL10.1.400.0\Source\Server\Services\BO\CustCnt\CustCnt.cs:line 1657
at Erp.Services.BO.CustCntSvc.CustCntBeforeUpdate() in c:_Releases\ERP\RL10.1.400.0\Source\Server\Services\BO\CustCnt\CustCnt.cs:line 884
at Ice.Services.Trace.TablesetProfilingCollector.DoRowEventTrace(String tableName, String methodName, Int32 rowCount, Action action) in c:_Releases\ICE\3.1.400.10\source\Framework\Epicor.Ice\Services\TablesetProfilingCollector.cs:line 144
at Ice.TablesetBound3.UpdateRow(IceDataContext dataContext, Int32 tableNum, IIceTable table, IceRow updatedRow, IceRow originalRow, TablesetProfilingCollector parentTraceCollector) in c:\_Releases\ICE\3.1.400.10\source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 1155 at Ice.TablesetBound3.WriteTable(IceDataContext dataContext, Int32 tableIndex, IIceTable table, TablesetProfilingCollector parentTraceCollector) in c:_Releases\ICE\3.1.400.10\source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 894
at Ice.TablesetBound3.InnerUpdate(IceDataContext dataContext, TFullTableset tableset) in c:\_Releases\ICE\3.1.400.10\source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 796 at Erp.Services.BO.CustCntSvc.Update(CustCntTableset& ds) in c:\_Releases\ERP\RL10.1.400.0\Source\Server\Services\BO\CustCnt\CustCnt.Designer.cs:line 848 at Epicor.Customization.Bpm.MethodCustomizationBase23.RunDirectives(TParam parameters) in c:_Releases\ICE\3.1.400.10\source\Server\Internal\Lib\Epicor.Customization.BPM\MethodCustomizationBase2.cs:line 218
at Epicor.Customization.Bpm.CustomizationBase23.Execute(TParam parameters) in c:\_Releases\ICE\3.1.400.10\source\Server\Internal\Lib\Epicor.Customization.BPM\CustomizationBase2.cs:line 77 at Epicor.Customization.Bpm.BO177D37D68398474098FA410429D05638.CustCntSvcCustomization.Update(CustCntTableset& ds) at Erp.Services.BO.CustCntSvcFacade.Update(CustCntTableset& ds) in c:\_Releases\ERP\RL10.1.400.0\Source\Server\Services\BO\CustCnt\CustCntSvcFacade.cs:line 213 at SyncInvokeUpdate(Object , Object[] , Object[] ) at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) at Epicor.Hosting.OperationBoundInvoker.InnerInvoke(Object instance, Func2 func) in c:_Releases\ICE\3.1.400.10\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.400.10\source\Framework\Epicor.System\Hosting\OperationBoundInvoker.cs:line 28

Any ideas?

Tim

Are you using the WCF Services outside of Epicor? If so you may need to clone the Record in order for the Update to work correctly.

Note this will “break” your for each loop so you may have to move to a for loop or some other mechanism.


    if (cnt.LastName == “VonDerHaar”)
    {
        CustCntRow backUpRow = new CustCntRow();
        var fields = backUpRow.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
        foreach(var field in fields)
        {
            if (field.PropertyType == typeof(System.Runtime.Serialization.ExtensionDataObject))
                continue;
            var fieldValue = field.GetValue(cnt);
            field.SetValue(backUpRow, fieldValue);
        }
        custcnt.CustCnt.Add(backUpRow);
        Cnt.FirstName = “Test”;
        Cnt.RowMod = “U”;
        Custcntclient.Update(ref custcnt);

}
1 Like

Curious. I am using the services outside of Epicor so I guess this would apply, but why would things act differently with the CustCnt service than it did with the Customer service?

Also feels and looks strange to have to do a .Add when it’s really an update.

ITs not an add, you are adding a a row to the data set to let it know what the previous version was (ttPrev, vs ttPost) some BO’s work without it. Give it a shot and see

Seems to do the trick. Very grateful for your help. Crazy that all BOs don’t work the same.

Technically you should do that for every BO.
See coming from 9 you used to have a before and a changed record.
In order to use BPMs with conditions such as field z change from x to y