Skip to main content
Solved

Transaction Were DeadLocked when releasing invoice

  • September 28, 2023
  • 6 replies
  • 169 views

abdallaahmed61
Varsity III
Forum|alt.badge.img+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 ?

Best answer by vardan22

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

View original
Did this topic help you find an answer to your question?

6 replies

jinin
Pro I
Forum|alt.badge.img+11
  • Pro I
  • 701 replies
  • September 28, 2023

Hi @abdallaahmed61 ,

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


abdallaahmed61
Varsity III
Forum|alt.badge.img+1
jinin wrote:

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


vardan22
Jr Varsity III
Forum|alt.badge.img+1
  • Jr Varsity III
  • 44 replies
  • October 1, 2023

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.


abdallaahmed61
Varsity III
Forum|alt.badge.img+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

vardan22 wrote:

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.


vardan22
Jr Varsity III
Forum|alt.badge.img+1
  • Jr Varsity III
  • 44 replies
  • Answer
  • October 4, 2023

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


abdallaahmed61
Varsity III
Forum|alt.badge.img+1
vardan22 wrote:

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


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings