StaleObjectStateException: Row was updated or deleted by another transaction in JPA - jpa-2.0

I have the ManyToOne Relationship in "Letter.java" as follows;
#ManyToOne(fetch = FetchType.EAGER)
private Letter inResponseTo;
With one Letter object multiple inResponseTo of the same Letter type of objects are associated.For the Letter object all the inResponseTo objects are getting updated so initially i am merging() them within the loop and finally persisting() the Letter object as follows;
private void saveCorrespondence(List<Letter> letterList,
final Claimant claimant) {
for (Letter letter : letterList) {
if(letter.getLetterCode() == null) {
if(letter.getMailType() == MailType.OUTGOING) {
letter.setLetterCode(LetterCode.findByCode("701"));
} else if(letter.getMailType() == MailType.INCOMING) {
letter.setLetterCode(LetterCode.findByCode("109"));
}
}
letter.setClaimant(claimant);
if (letter.getId() != null) {
letter = letter.merge();
letter.flush();
}
letter.persist();//Here in this line i am getting an error.
}
}
Note:-Claimant and Letter have OneToMany relationship.
While persisting getting the Error as StaleObjectStateException: Row was updated or deleted by another transaction JPA in the same Line.How I can fix this please help me.

Related

How to pass LedgerJournalTrans table in resolve method of InvoiceJournalExpPartcicipantProvider class?

I have literally tried everything but still in vain. This here is InvoiceJournalExpParticipantProvider class that is supposed to provide me partici[ant names inside the workflow (all of this is custom code). Now what i want is to pass the LedgerJounalTrans table instead of the VendInvoiceInfoTable or VendInvoiceInfoLine table. I cannot seem to find a way to do this. I tried using the following code
else if (_context.parmTableId() == tableNum(LedgerJournalTrans))
{
ledgerJournalTrans = LedgerJournalTrans::findRecId(_context.parmRecId(),false);
}
But it constantly gives me an error either telling me that the operand types are of not the same types or the number of arguments passed are invalid although when i go and check the findRecId() method of ledgerJournalTrans table there are only two params being passed.
public WorkflowUserList resolve(WorkflowContext _Context, WorkflowParticipantToken _participantTokenName)
{
WorkflowUserList userList = WorkflowUserList::construct();
VendInvoiceInfoTable vendInvoiceInfoTable;
VendInvoiceInfoLine vendInvoiceInfoLine;
VendInvoiceInfoLine_Project vendInvoiceInfoLine_Project;
WorkflowParticipantExpenToken workflowParticipantExpenToken;
WorkflowParticipantExpenTokenLine workflowParticipantExpenTokenLine;
RefRecId dimensionAttributeSetRecId;
MarkupTrans markupTrans;
CompanyInfo legalEntity;
ProjTable projTable;
HcmWorker worker;
DirPersonUser personUser;
HcmPositionDetail hcmPositionDetail;
HcmPosition hcmPosition;
HcmPositionWorkerAssignment hcmPositionWorkerAssignment;
LedgerJournalTrans ledgerJournalTrans;
// check participant token name is given otherwise throw error
if(!_participantTokenName)
{
throw error('Participant name');
}
userList.add('Admin');
if (!_participantTokenName)
{
throw error("#SYS105453");
}
workflowParticipantExpenToken = WorkflowParticipantExpenToken::findName(
this.documentType(),
_participantTokenName);
if (!workflowParticipantExpenToken)
{
throw error(strFmt("#SYS313865", _participantTokenName));
}
if (_context.parmTableId() == tableNum(VendInvoiceInfoTable))
{
vendInvoiceInfoTable = VendInvoiceInfoTable::findRecId(_context.parmRecId());
}
else if (_context.parmTableId() == tableNum(VendInvoiceInfoLine))
{
vendInvoiceInfoTable = VendInvoiceInfoLine::findRecId(_context.parmRecId()).vendInvoiceInfoTable();
}

dart - how do check id/name if contains in List?

I have a case when the user wants to add a product to the cart, before that I want to check the id/name product whether or not he was in the cart.
if not then I will add it to the cart, if its already there I will just do edit (adding qty and price)
I have tried using the code below:
Future checkIfProductHasAdded(String uid) async {
for (var i = 0; i < _checkoutList.length; i++) {
print(_checkoutList[i].name);
if (_checkoutList[i].productName == getSelectedProduct.name) {
selectedProductCheckout(i);
print(getSelectedProduct.name +
"PRODUCT CHECKOUT HAS ADDED" +
_checkoutList[i].productName);
// await updateProductCheckout(uid);
break;
} else {
print(getSelectedProduct.name + "NOT FOUND AT PRODUCT CHECKOUT");
//await addProductToCheckout(uid);
break;
}
}
}
when I print() value i does not specify the position on the List, but stays in position 0.
how to make it work?
any answer will be appreciated.
You should check if a product exists in firstWhere clause.
Something like this:
var product = _checkoutList.firstWhere((product) => product.productName == getSelectedProduct.name, orElse: () => null);
if (product == null) addProductToCheckout(uid);
else updateProductCheckout(uid);
This solution is the quickest :
final bool _productIsInList =
_checkoutList.any((product) => product.name == getSelectedProduct.name);
if (_productIsInList) {
// The list contains the product
} else {
// The list does not contain the product
}
NOTE :
If you don't need to compare IDs/names, but you just want to check if a specific item is in a list, you can use _checkoutList.contains(item)

Acumatica - Adding Multiple Tracking Numbers in Field

I am adding the Tracking Number data field from SOPackageDetail to the Invoices screen (SO303000) on the Freight Details Tab. I know that it only shows one ShipmentNbr and this is what I'm using to join the two tables but I would like all of the tracking numbers, since there can be more than one per shipment number, to show in the field instead of just one. They can be just separated in the field value by a comma. Here is my code and it does work for just one tracking number.
Graph:
public class SOInvoiceEntry_Extension : PXGraphExtension<SOInvoiceEntry>
{
#region Event Handlers
protected void SOFreightDetail_RowSelecting(PXCache cache, PXRowSelectingEventArgs e, PXRowSelecting del)
{
if (del != null)
del(cache, e);
var row = (SOFreightDetail)e.Row;
if (row == null) return;
using (new PXConnectionScope())
{
SOPackageDetail track = PXSelect<SOPackageDetail, Where<SOPackageDetail.shipmentNbr, Equal<Required<SOFreightDetail.shipmentNbr>>>>.Select(Base, row.ShipmentNbr);
if(track != null){
SOFreightDetailExt invoiceExt = row.GetExtension<SOFreightDetailExt>();
if (invoiceExt != null){
invoiceExt.TrackNumber = track.TrackNumber;
}
}
}
}
#endregion
}
DAC Extension:
public class SOFreightDetailExt : PXCacheExtension<PX.Objects.SO.SOFreightDetail>
{
#region TrackNumber
public abstract class trackNumber : PX.Data.IBqlField
{
}
protected string _TrackNumber;
[PXString()]
[PXDefault()]
[PXUIField(DisplayName = "Tracking Number", IsReadOnly = true)]
public virtual string TrackNumber
{
get
{
return this._TrackNumber;
}
set
{
this._TrackNumber = value;
}
}
#endregion
}
I want all tracking numbers associated with the Shipment Nbr to be displayed in this field, right now it only shows one. This only will happen if there is multiple packages for one shipment number.
You need to loop on your records (PXSelect) in a foreach. You then need to add each string value to your tracknumber field. Something like this should work...
SOFreightDetailExt invoiceExt = row.GetExtension<SOFreightDetailExt>();
if(invoiceExt == null)
return;
foreach(SOPackageDetail track in PXSelect<SOPackageDetail, Where<SOPackageDetail.shipmentNbr, Equal<Required<SOFreightDetail.shipmentNbr>>>>.Select(Base, row.ShipmentNbr))
{
invoiceExt.TrackNumber = $"{invoiceExt.TrackNumber}, {track.TrackNumber}";
}
Also, there is no need for the PXConnectionScope. You can remove that.

Refreshing a list of webelements after delete line

I am writing an automated test for a dynamic webtable using Selenium Webdriver with chromedriver and testNG.
The objective is to assert that a certain table-entry is there, delete it if it is, and then assert if it is deleted. This second assert is not working properly however.
During the first assert I call the method that creates a list of Webelements and gets the number of rows. I use this number to know when to stop iterating through the table.
The second assert uses the same table to do the same thing, but now the DOM has changed, en there are only 18 rules left in my table were there were 19 before. As soon as the iteration tries to get the 19th row I get the following:
org.openqa.selenium.NoSuchElementException: no such element: Unable to
locate element: {"method":"xpath","selector":".//tr[19]/td[1]"}
I have tried creating a new instance of the MyWishlistPage, but this new instance also sees the "old" number of table rules
I have also tried a thread sleep and a driver refresh after the row delete, but this doesn't help either (piece of code is still there, commented)
I ended up altering my test class to go to another page and then return to the MYWishlistPage. This works, but it's a sloppy workaround that I'm not happy with
Can anyone tell me how I can get the correct number of rows after deleting an entry from the table?
This is a piece of the class for the page that I have the problem with :
public class MyWishlistsPage
{
private WebDriver driver;
public MyWishlistsPage(WebDriver driver)
{
this.driver = driver;
//This call sets the WebElements
PageFactory.initElements(driver, this);
}
public Boolean isWishlistAvailable(String nameToAssert)
{
//This list gets the number of rows from the table
List<WebElement> rows = driver.findElements(By.xpath(".//tr"));
//This loop finds the first row which' title matches sRowValue
for (int i = 1; i < rows.size(); i++)
{
String sValue = driver.findElement(By.xpath(".//tr[" + i + "]/td[1]")).getText();
if (sValue.equalsIgnoreCase(nameToAssert))
{
return true;
}
}
return false;
}
public void deleteWishlistsEntry (String sRowValue)
{
//This list gets the number of rows from the table
List<WebElement> rows = driver.findElements(By.xpath(".//tr"));
//This loop finds the first row which' title matches sRowValue
for (int i = 1; i < rows.size(); i++)
{
String sValue = driver.findElement(By.xpath(".//tr[" + i + "]/td[1]")).getText();
if (sValue.equalsIgnoreCase(sRowValue))
{
// If the sValue matches with the description, the element in the seventh column of the row will be clicked
driver.findElement(By.xpath(".//tr[" + i + "]/td[7]/a/i")).click();
driver.switchTo().alert().accept();
/* try
{
Thread.sleep(10000);
} catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
driver.navigate().refresh(); */
}
}
}
}
This is a piece of the testclass I am calling the page from :
Assertions.assertThat(mywishlistspage.isWishlistAvailable(listToAssert)).as("The list you were trying to delete did not exist, and an attempt to create it failed ").isTrue();
//Deletes the chosen list
mywishlistspage.deleteWishlistsEntry(listToAssert);
//Verifies that list has been deleted
//homepage.clickMyAccountPage();
//myaccountpage.goToMyWishlistsPage();
Assertions.assertThat(mywishlistspage.isWishlistAvailable(listToAssert)).as("The list you tried to delete is still there").isFalse();
In the deleteWishlistsEntry, First it get the number of rows, after clicking on the "anchor" the line item will be deleted, after that u have to break / exit from that loop once it clicked on the anchor tag... But in the code u r looping until the 19th element that is why u get "Unable to locate element: {"method":"xpath","selector":".//tr[19]/td[1]"}"
public void deleteWishlistsEntry (String sRowValue)
{
//This list gets the number of rows from the table
List<WebElement> rows = driver.findElements(By.xpath(".//tr"));
//This loop finds the first row which' title matches sRowValue
for (int i = 1; i < rows.size(); i++)
{
String sValue = driver.findElement(By.xpath(".//tr[" + i + "]/td[1]")).getText();
if (sValue.equalsIgnoreCase(sRowValue))
{
// If the sValue matches with the description, the element in the seventh column of the row will be clicked
driver.findElement(By.xpath(".//tr[" + i + "]/td[7]/a/i")).click();
driver.switchTo().alert().accept();
break;
}
}
}

java.lang.AssertionError: expected

My TestNG test implementation throws an error despite the expected value matches with the actual value.
Here is the TestNG code:
#Test(dataProvider = "valid")
public void setUserValidTest(int userId, String firstName, String lastName){
User newUser = new User();
newUser.setLastName(lastName);
newUser.setUserId(userId);
newUser.setFirstName(firstName);
userDAO.setUser(newUser);
Assert.assertEquals(userDAO.getUser().get(0), newUser);
}
The error is:
java.lang.AssertionError: expected [UserId=10, FirstName=Sam, LastName=Baxt] but found [UserId=10, FirstName=Sam, LastName=Baxt]
What have I done wrong here?
The reason is simple. Testng uses the equals method of the object to check if they're equal. So the best way to achieve the result you're looking for is to override the equals method of the user method like this.
public class User {
private String lastName;
private String firstName;
private String userId;
// -- other methods here
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!User.class.isAssignableFrom(obj.getClass())) {
return false;
}
final User other = (User) obj;
//If both lastnames are not equal return false
if ((this.lastName == null) ? (other.lastName != null) : !this.lastName.equals(other.lastName)) {
return false;
}
//If both lastnames are not equal return false
if ((this.firstName == null) ? (other.firstName != null) : !this.firstName.equals(other.firstName)) {
return false;
}
//If both lastnames are not equal return false
if ((this.userId == null) ? (other.userId != null) : !this.userId.equals(other.userId)) {
return false;
}
return true;
}
}
and it'll work like magic
It seems you are either comparing the wrong (first) object or equals is not correctly implemented as it returns false.
The shown values are just string representations. It doesn't actually mean that both objects have to be equal.
You should check if userDAO.getUser().get(0) actually returns the user you are setting before.
Posting the implementation of User and the userDAO type might help for further clarification.
NOTE: Note directly related to this question but it's answer to my issue that got me to this question. I am sure more ppl might end-up on this post looking for this solution.
This is not precisely the a solution if Equals method needs overriding but something that I very commonly find myself blocked due to:
If you have used Capture and are asserting equality over captured value, please be sure to get the captured value form captured instance.
eg:
Capture<Request> capturedRequest = new Capture<>();
this.testableObj.makeRequest(EasyMock.capture(capturedRequest))
Assert.assertEquals(capturedRequest.getValue(), expectedRequest);
V/S
Assert.assertEquals(capturedRequest, expectedRequest);
while the compiler wont complain in either case, the Assertion Obviously fails in 2nd case