Solved

Transaction Were DeadLocked when releasing invoice

  • 28 September 2023
  • 6 replies
  • 120 views

Userlevel 3
Badge +1

i have put a pxTransaction in the release button in the invoices screen .

its working but it sometimes gets deadlocked by another process 

DeadLock Img

 

This is the code that i think makes the problem

using (PXTransactionScope ts = new PXTransactionScope())
{
PXDatabase.Update<MixPayments>(new PXDataFieldAssign<MixPayments.docType>(inv.DocType),
new PXDataFieldAssign<MixPayments.refNbr>(inv.RefNbr),
new PXDataFieldRestrict<MixPayments.orderNbr>(mix.OrderNbr),
new PXDataFieldRestrict<MixPayments.orderType>(mix.OrderType));
ts.Complete();
}

is there a way to use with nolock in acumatica like SQL ?

or is there another way to make this code work ?

icon

Best answer by vardan22 4 October 2023, 14:42

View original

6 replies

Userlevel 7
Badge +11

Hi @abdallaahmed61 ,

Could you perform the update using the graph object instead of DBupdate?

Userlevel 3
Badge +1

Hi @abdallaahmed61 ,

Could you perform the update using the graph object instead of DBupdate?

could you show me how ? because i used this code and it gave me this error

PXCache targetCache = mixPaymentsGraph.Caches[typeof(MixPayments)];

MixPayments targetRow = (MixPayments)targetCache.Current;
if (targetRow == null)
{
targetRow = (MixPayments)targetCache.Insert(mix);
}

targetRow.RefNbr = refNbr;
targetRow.DocType = tranType;

targetCache.Update(targetRow);
mixPaymentsGraph.Actions.PressSave();

 

and this code also gave me the same error 

mixPaymentsGraph.mix.Insert(mix);

mix.RefNbr = inv.RefNbr;
mix.DocType = inv.DocType;

mixPaymentsGraph.mix.Update(mix);

im putting this code in the Release button in the sales orders screen

Userlevel 4
Badge +1

This is due to running internal processes. To figure out which processes might be blocking each other, you should show the entire process you are trying to run (calling actions, methods, etc.).


Transaction deadlocked error refers to database updates and means that two different processes are trying to change the same record in the same SQL table at the same time.

Userlevel 3
Badge +1
public delegate IEnumerable ReleaseDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{

ARInvoice inv = Base.Document.Current;

string soType = Base.Transactions.Current.SOOrderType;
string soNbr = Base.Transactions.Current.SOOrderNbr;

bool transactionExists = PXTransactionScope.IsScoped;

try
{
var mixPayments = Pay.Select(soNbr, soType);

MixPaymentsEntry mixPaymentsGraph = PXGraph.CreateInstance<MixPaymentsEntry>();

foreach (MixPayments mix in mixPayments)
{
if (mix.RefNbr is null || mix.DocType is null || mix.RefNbr == " <NEW>")
{
if (!transactionExists)
{
using (PXTransactionScope scope = new PXTransactionScope())
{
PXDatabase.Update<MixPayments>(new PXDataFieldAssign<MixPayments.docType>(inv.DocType),
new PXDataFieldAssign<MixPayments.refNbr>(inv.RefNbr),
new PXDataFieldRestrict<MixPayments.orderNbr>(mix.OrderNbr),
new PXDataFieldRestrict<MixPayments.orderType>(mix.OrderType));
scope.Complete();
}
}
else
{
PXDatabase.Update<MixPayments>(new PXDataFieldAssign<MixPayments.docType>(inv.DocType),
new PXDataFieldAssign<MixPayments.refNbr>(inv.RefNbr),
new PXDataFieldRestrict<MixPayments.orderNbr>(mix.OrderNbr),
new PXDataFieldRestrict<MixPayments.orderType>(mix.OrderType));
}
break;
}
}
}
catch (Exception)
{

}

baseMethod(adapter);
return adapter.Get();
}

This is my release Action Button code.

I

This is due to running internal processes. To figure out which processes might be blocking each other, you should show the entire process you are trying to run (calling actions, methods, etc.).


Transaction deadlocked error refers to database updates and means that two different processes are trying to change the same record in the same SQL table at the same time.

 

added the ‘transactionExists’  check but still didn't test it.

Userlevel 4
Badge +1

Unfortunately from this code, I can’t say what the exact problem is, but I can suggest some changes which will help to avoid errors like this.

From this code, I saw you have a graph MixPaymentsEntry created for the MixPayments record. I hope this graph can be used for data manipulation in the MixPayments table.

  • It is not necessary to use PXTransactionScope if the code uses only DB direct operation. In this code, you can just remove the PXTransactionScope.
  • If the MixPayments records update depends on the Invoice Release process the best practice is to override the ReleaseInvoiceProc method and write your code before or after calling base method.
 public delegate void ReleaseInvoiceProcDelegate(List<ARRegister> list, bool isMassProcess);
[PXOverride]
public void ReleaseInvoiceProc(List<ARRegister> list, bool isMassProcess, ReleaseInvoiceProcDelegate releaseInvoiceProc)
{
using (PXTransactionScope scope = new PXTransactionScope())
{
//TODO add your code here
releaseInvoiceProc(list, isMassProcess);
//TODO add your code here
scope.Complete();
}
}

You can write code without direct database updates, as @jinin pointed out above.

For example something like this: 

 public virtual void UpdateMixPayments(List<ARRegister> list)
{
foreach (ARRegister arregister in list)
{
ARInvoice invoice = ARInvoice.PK.Find(this.Base, arregister.DocType, arregister.RefNbr);

ARTran invLine = ARTran.FK.Invoice.SelectChildren(Base, invoice).FirstOrDefault();
if (invLine != null)
{
var mixPayments = Pay.Select(invLine.SOOrderNbr, invLine.SOOrderType);

MixPaymentsEntry mixPaymentsGraph = PXGraph.CreateInstance<MixPaymentsEntry>();

foreach (MixPayments mix in mixPayments)
{
mixPaymentsGraph.Clear();
if (mix.RefNbr is null || mix.DocType is null || mix.RefNbr == " <NEW>")
{
mixPaymentsGraph.MixPayments.Current = mix;//Where MixPayments is primary view of MixPaymentsEntry graph
mixPaymentsGraph.MixPayments.Current.DocType = invoice.DocType;
mixPaymentsGraph.MixPayments.Current.RefNbr = invoice.RefNbr;
mixPaymentsGraph.MixPayments.Update(mixPaymentsGraph.MixPayments.Current);
mixPaymentsGraph.Save.Press();
}
}
}
}
}

Of course, the code written inside of second foreach loop depends on which type graph is MixPaymentsEntry. If it is the ListView the calling Clear() and Save action can be out of the foreach.

Then call this method during the process where you want to update records

Userlevel 3
Badge +1

Unfortunately from this code, I can’t say what the exact problem is, but I can suggest some changes which will help to avoid errors like this.

From this code, I saw you have a graph MixPaymentsEntry created for the MixPayments record. I hope this graph can be used for data manipulation in the MixPayments table.

  • It is not necessary to use PXTransactionScope if the code uses only DB direct operation. In this code, you can just remove the PXTransactionScope.
  • If the MixPayments records update depends on the Invoice Release process the best practice is to override the ReleaseInvoiceProc method and write your code before or after calling base method.
 public delegate void ReleaseInvoiceProcDelegate(List<ARRegister> list, bool isMassProcess);
[PXOverride]
public void ReleaseInvoiceProc(List<ARRegister> list, bool isMassProcess, ReleaseInvoiceProcDelegate releaseInvoiceProc)
{
using (PXTransactionScope scope = new PXTransactionScope())
{
//TODO add your code here
releaseInvoiceProc(list, isMassProcess);
//TODO add your code here
scope.Complete();
}
}

You can write code without direct database updates, as @jinin pointed out above.

For example something like this: 

 public virtual void UpdateMixPayments(List<ARRegister> list)
{
foreach (ARRegister arregister in list)
{
ARInvoice invoice = ARInvoice.PK.Find(this.Base, arregister.DocType, arregister.RefNbr);

ARTran invLine = ARTran.FK.Invoice.SelectChildren(Base, invoice).FirstOrDefault();
if (invLine != null)
{
var mixPayments = Pay.Select(invLine.SOOrderNbr, invLine.SOOrderType);

MixPaymentsEntry mixPaymentsGraph = PXGraph.CreateInstance<MixPaymentsEntry>();

foreach (MixPayments mix in mixPayments)
{
mixPaymentsGraph.Clear();
if (mix.RefNbr is null || mix.DocType is null || mix.RefNbr == " <NEW>")
{
mixPaymentsGraph.MixPayments.Current = mix;//Where MixPayments is primary view of MixPaymentsEntry graph
mixPaymentsGraph.MixPayments.Current.DocType = invoice.DocType;
mixPaymentsGraph.MixPayments.Current.RefNbr = invoice.RefNbr;
mixPaymentsGraph.MixPayments.Update(mixPaymentsGraph.MixPayments.Current);
mixPaymentsGraph.Save.Press();
}
}
}
}
}

Of course, the code written inside of second foreach loop depends on which type graph is MixPaymentsEntry. If it is the ListView the calling Clear() and Save action can be out of the foreach.

Then call this method during the process where you want to update records

thnx alot for your answer i will try and test it 

Reply


About Acumatica ERP system
Acumatica Cloud ERP provides the best business management solution for transforming your company to thrive in the new digital economy. Built on a future-proof platform with open architecture for rapid integrations, scalability, and ease of use, Acumatica delivers unparalleled value to small and midmarket organizations. Connected Business. Delivered.
© 2008 — 2024  Acumatica, Inc. All rights reserved