OneToOne relationship doesn't always fetch - java

I have a OneToOne relationship between two tables, as shown below:
PreRecordLoad.java:
#OneToOne(mappedBy="preRecordLoadId",cascade = CascadeType.ALL)
private PreRecordLoadAux preRecordLoadAux;
PreRecordLoadAux.java:
#JoinColumn(name = "PRE_RECORD_LOAD_ID", referencedColumnName = "PRE_RECORD_LOAD_ID")
#OneToOne
private PreRecordLoad preRecordLoadId;
I'm using this method to pull back the PreRecordLoad object:
public PreRecordLoad FindPreRecordLoad(Long ID)
{
print("Finding " + ID + "f");
Query query;
PreRecordLoad result = null;
try
{
query = em.createNamedQuery("PreRecordLoad.findByPreRecordLoadId");
query.setParameter("preRecordLoadId", ID);
result = (PreRecordLoad)query.getSingleResult();
//result = em.find(PreRecordLoad.class, ID);
}
catch(Exception e)
{
print(e.getLocalizedMessage());
}
return result;
}
The '+ "f"' is to see if the passed value somehow had something at the end. It didn't.
I originally used em.find, but the same issue occurred no matter which method I used.
I used to use a BigDecimal for the ID because it was the default, and noticed I was getting a precision difference when it worked, and when it didn't work. Specifically the precision was 4 when it didn't work, but 0 when it did. I couldn't work out why this was, so I changed the BigDecimal to a Long, as I never really needed it to be a BigDecimal anyway.
When I save the new PreRecordLoad and PreRecordLoadAux objects to the database (inserting them for the first time), and then try and run this method to recall the objects, it retrieves the PreRecordLoad, but the PreRecordLoadAux is null. This is despite the entry being in the database and what looks to be full committed, as I can access it from SQLDeveloper, which is a separate session.
However, if I stop and re-run the application, then it successfully pulls back both objects. The ID being passed is the same both times, or at least appears to be.
Anyway suggestions would be greatly appreciated, thankyou.
Edit:
Here is the code for when I am persisting the objects into the DB:
if(existingPreAux==null) {
try {
preLoad.setAuditSubLoadId(auditLoad);
em.persist(preLoad);
print("Pre Record Load entry Created");
preAux.setPreRecordLoadId(preLoad);
em.persist(preAux);
print("Pre Record Load Aux entry Created");
}
catch(ConstraintViolationException e) {
for(ConstraintViolation c : e.getConstraintViolations()) {
System.out.println (c.getPropertyPath() + " " + c.getMessage());
}
}
}
else {
try {
preLoad.setPreRecordLoadId(existingPreLoad.getPreRecordLoadId());
preLoad.setAuditSubLoadId(auditLoad);
em.merge(preLoad);
print("Pre Record Load entry found and updated");
preAux.setPreRecordLoadAuxId(existingPreAux.getPreRecordLoadAuxId());
preAux.setPreRecordLoadId(preLoad);
em.merge(preAux);
print("Pre Record Load Aux entry found and updated");
}
catch(ConstraintViolationException e) {
for(ConstraintViolation c : e.getConstraintViolations()) {
System.out.println (c.getPropertyPath() + " " + c.getMessage());
}
}
}
That's in a method, and after that code, the method ends.

It's your responsibility to maintain the coherence of the object graph. So, when you do preAux.setPreRecordLoadId(preLoad);, yo must also do preLoad.setPreRecordLoadAux(preAux);.
If you don't, then every time you'll load the preAux from the same session, it will be retrieved from the first-level cache, and will thus return your incorrectly initialized instance of the entity.

Related

Spring boot application gets stuck when executing a repository method call

I have a service method which is transactional. This method saves an Entity called FascicoloENT on the database after some updates done with mapstruct. Before the entity is saved, FascicoloRepository is called by internal business logig to get the maximum value of a column in the fascicolo Table. After the Entity is saved, onother method is called which, given the Fascicolo id, saves a new entity called RicorsoENT in the db. FacicoloENT and RicorsoENT are in a one to many jpa relation.
It happens that the java application gets stuck when the FacicoloRepository is called to get the maximum value needed by business logic. Although, from logs I can see that the application stops on a different query, when saving FascicoloENT, even though the code in debug hasn't yet reached that point...
Here is my service method:
#Override
#Transactional(rollbackFor = {Exception.class})
public FascicoloDTO updateFascicoloInCompleto(FascicoloDTO fascicolo, Long id) throws LedaException {
boolean isFirstSave = false;
var optionalFascicoloEntity = fascicoloRepository.findById(id);
if (optionalFascicoloEntity.isEmpty()) {
log.error(FascicoloApiConstants.FASCICOLO_CON_ID + " {}" + FascicoloApiConstants.NON_TROVATO, id);
throw new LedaNotFoundException(ErroreEnum.FASCICOLO_NON_TROVATO, FascicoloApiConstants.FASCICOLO_CON_ID + " " + id + FascicoloApiConstants.NON_TROVATO);
}
var fascicoloEntity = optionalFascicoloEntity.get();
LedaUtils.checkUpdatedId(id, fascicoloEntity.getId(), FascicoloApiConstants.ID_RISORSA_AGGIORNATA);
if (StatoEnum.BOZZA.equals(fascicoloEntity.getStato())) {
isFirstSave = true;
}
fascicoloMapper.updateFromDto(fascicolo, fascicoloEntity);
fascicoloEntity.setStato(StatoEnum.COMPLETO);
//Generazione numero fascicolo
var count = fascicoloRepository.getMaxCounter();
if (count == null) {
count = 1L;
fascicoloEntity.setCounterNumeroFascicolo(count);
} else {
count++;
fascicoloEntity.setCounterNumeroFascicolo(count);
}
String numeroFascicolo = "" + fascicoloEntity.getAnnoDiCompetenza() + count + fascicoloEntity.getUnitaOrganizzativa();
fascicoloEntity.setNumeroFascicolo(numeroFascicolo);
var fascicoloSalvato = fascicoloRepository.save(fascicoloEntity);
//Se il fascicolo passa in stato COMPLETO per la prima volta allora creo il ricorso
if (isFirstSave)
ricorsoService.createRicorso(fascicoloSalvato.getId());
log.info(FascicoloApiConstants.FASCICOLO_CON_ID + " {} " + FascicoloApiConstants.AGGIORNATO, id);
return fascicoloMapper.toApiModel(fascicoloSalvato);
}
The method where the code stops is the fascicoloRepository.getMaxCounter()
Here is the createRicorso method of the RicorsoService class:
#Transactional(rollbackFor = {Exception.class})
public RicorsoDTO createRicorso(Long idFascicolo) throws LedaException {
LedaUtils.checkNull(idFascicolo, "id risorsa");
var fascicoloENT = fascicoloRepository.getReferenceById(idFascicolo);
var ricorsoENT = new RicorsoENT();
ricorsoENT.setFascicolo(fascicoloENT);
ricorsoENT.setStato(StatoRicorsoEnum.APERTO);
return ricorsoMapper.toApiModelRicorso(ricorsoRepository.save(ricorsoENT));
}
Operations on FascicoloENT are not cascaded on RicorsoENT. There is no cascade type.
This is the query taken from logs where the code stops:
Hibernate:
update
tb_fascicoli
set
row_updated_dttm=?,
row_created_dttm=?,
row_updated_user=?,
row_created_user=?,
anno_competenza=?,
count_numero_fascicolo=?,
data_apertura=?,
flag_unito=?,
id_motivo_apertura=?,
id_motivo_arichiviazione=?,
note=?,
numero_fascicolo=?,
numero_fascicolo_unito=?,
numero_ricorrenti=?,
fk_ricorrente_principale=?,
id_sede_tar=?,
stato=?,
step=?,
terzo_interessato=?,
tipologia_ricorso=?,
unita_organizzativa=?
where
id=?
I tried deliting #Transactional on CreateRicorso method but it still doesn't work.
I think the problem is a metter of transactions or threads...
Can anyone help me understand why the application gets stuck and how to solve?
PS: let me know if you need extra information
Many thanks,
Saverio

bitcoinJ get transaction value

I downloaded a lot of blockchain data using https://bitcoin.org, I took some file and I try to analyse it with bitcoinj library.
I would like to get information from every transaction:
-who send bitcoins,
-how much,
-who receive bitcoins.
I use:
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.15.10</version>
</dependency>
I have a code:
NetworkParameters np = new MainNetParams();
Context.getOrCreate(MainNetParams.get());
BlockFileLoader loader = new BlockFileLoader(np,List.of(new File("test/resources/blk00450.dat")));
for (Block block : loader) {
for (Transaction tx : block.getTransactions()) {
System.out.println("Transaction ID" + tx.getTxId().toString());
for (TransactionInput ti : tx.getInputs()) {
// how to get wallet addresses of inputs?
}
// this code works for 99% of transactions but for some throws exceptions
for (TransactionOutput to : tx.getOutputs()) {
// sometimes this line throws: org.bitcoinj.script.ScriptException: Cannot cast this script to an address
System.out.println("out address:" + to.getScriptPubKey().getToAddress(np));
System.out.println("out value:" + to.getValue().toString());
}
}
}
Can you share some snippet that will work for all transactions in the blockchain?
There are at least two type of transaction, P2PKH and P2SH.
Your code would work well with P2PKH, but wouldn not work with P2SH.
You can change the line from:
System.out.println("out address:" + to.getScriptPubKey().getToAddress(np));
to:
System.out.println("out address:" + to.getAddressFromP2PKHScript(np)!=null?to.getAddressFromP2PKHScript(np):to.getAddressFromP2SH(np));
The API of Bitcoin says the methods getAddressFromP2PKHScript() and getAddressFromP2SH() are deprecated, and I have not find suitable method.
However, P2SH means "Pay to Script Hash", which means it could contain two or more public keys to support multi-signature. Moreover, getAddressFromP2SH() returns only one address, perhaps this is the reason why it is deprecated.
I also wrote a convinient method to check the inputs and outputs of a block:
private void printCoinValueInOut(Block block) {
Coin blockInputSum = Coin.ZERO;
Coin blockOutputSum = Coin.ZERO;
System.out.println("--------------------Block["+block.getHashAsString()+"]------"+block.getPrevBlockHash()+"------------------------");
for(Transaction tx : block.getTransactions()) {
Coin txInputSum = tx.getOutputSum();
Coin txOutputSum = tx.getOutputSum();
blockInputSum = blockInputSum.add(txInputSum);
blockOutputSum = blockOutputSum.add(txOutputSum);
System.out.println("Tx["+tx.getTxId()+"]:\t" + txInputSum + "(satoshi) IN, " + txOutputSum + "(satoshi) OUT.");
}
System.out.println("Block total:\t" + blockInputSum + "(satoshi) IN, " + blockOutputSum + "(satoshi) OUT. \n");
}

Java unique code generation failed while calling the recurring function

We have to implement a logic to write the unique code generation in Java. The concept is when we generate the code the system will check if the code is already generate or not. If already generate the system create new code and check again. But this logic fails in some case and we cannot able to identify what is the issue is
Here is the code to create the unique code
Integer code = null;
try {
int max = 999999;
int min = 100000;
code = (int) Math.round(Math.random() * (max - min + 1) + min);
PreOrders preObj = null;
preObj = WebServiceDao.getInstance().preOrderObj(code.toString());
if (preObj != null) {
createCode();
}
} catch (Exception e) {
exceptionCaught();
e.printStackTrace();
log.error("Exception in method createCode() - " + e.toString());
}
return code;
}
The function preOrderObj is calling a function to check the code exists in the database if exists return the object. We are using Hibernate to map the database functions and Mysql on the backend.
Here is the function preOrderObj
PreOrders preOrderObj = null;
List<PreOrders> preOrderList = null;
SessionFactory sessionFactory =
(SessionFactory) ServletActionContext.getServletContext().getAttribute(HibernateListener.KEY_NAME);
Session Hibernatesession = sessionFactory.openSession();
try {
Hibernatesession.beginTransaction();
preOrderList = Hibernatesession.createCriteria(PreOrders.class).add(Restrictions.eq("code", code)).list(); // removed .add(Restrictions.eq("status", true))
if (!preOrderList.isEmpty()) {
preOrderObj = (PreOrders) preOrderList.iterator().next();
}
Hibernatesession.getTransaction().commit();
Hibernatesession.flush();
} catch (Exception e) {
Hibernatesession.getTransaction().rollback();
log.debug("This is my debug message.");
log.info("This is my info message.");
log.warn("This is my warn message.");
log.error("This is my error message.");
log.fatal("Fatal error " + e.getStackTrace().toString());
} finally {
Hibernatesession.close();
}
return preOrderObj;
}
Please guide us to identify the issue.
In createCode method, when the random code generated already exist in database, you try to call createCode again. However, the return value from the recursive call is not updated to the code variable, hence the colliding code is still returned and cause error.
To fix the problem, update the method as
...
if (preObj != null) {
//createCode();
code = createCode();
}
...
Such that the code is updated.
By the way, using random number to generate unique value and test uniqueness through query is a bit strange. You may try Auto Increment if you want unique value.

How to read an updated value that has not been committed within a transaction?

I'm using Avaje Ebean API to CRUD data from PostgreSQL DB. Here is my code:
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.ebean.SqlQuery;
import com.avaje.ebean.SqlUpdate;
...
class Example {
private void insertStockItem(PickingFieldProductItemDto dto, StockDao stockDao) {
try {
Ebean.beginTransaction();
List<PickingFieldProductItem> productList = dto.getItemList();
for(PickingFieldProductItem product : productList) {
StockDto stockDto = buildStockDto(product);
Stock stock = stockDao.getStockItem(stockDto.ID);
// stock.Quantity is always 500
if(stock != null) {
if(stock.getQuantity().compareTo(product.getOutcomingQuantity()) == 0)
stockDao.deleteStock(stockDto);
else {
int updateQuantity = stock.getQuantity() - product.getOutcomingQuantity();
// updateQuantity = 300 and I will update this value to stock table
int identity = stockDao.updateStock(stockDto.ID, updateQuantity);
}
}
}
Ebean.commitTransaction();
} catch (BusinessException e) {
Ebean.rollbackTransaction();
} finally {
Ebean.endTransaction();
}
}
}
My problem is:
At the 1st loop I get stock object and see the value of Quantity property is 500, then I update it with another value (300). The update statement ran successfully, I checked the identity var, it returns value 1.
But at the 2nd loop I get stock object again and now the value of Quantity property is still 500. My expectation is 300. Assumption that productList has only 2 elements.
Anyone can help me how to get the expected value? It's possible?
Thanks.

LDAP Not processing showing SchemaViolationException

I am having a LDAP Queue which process a object class.I cant find the exact location why it is giving the exception. The objclass is a concadenation string with pipe symbol. Any program coding to find the exact location in which concadination part is going to the Exception?.Please Assist.
try {
Attributes objClass = null;
try {
objClass = getObjClass(LdapInfo.PER_ID, person.perId);
} catch (NamingException e)
{
DCXError.myInstance().writeError("LdapUpdaterConnection: " + e.getMessage());
}
NamingEnumeration oc = objClass.get("objectclass").getAll();
String baseObjClass = null;
while (oc.hasMoreElements()) {
baseObjClass = (String) oc.nextElement();
if (baseObjClass.equalsIgnoreCase(LdapInfo.NON_EMPLOYEE_PERSON)
|| baseObjClass.equalsIgnoreCase("N/A")||
baseObjClass.equalsIgnoreCase(LdapInfo.EMPLOYEE_PERSON))
break;
}
} catch (SchemaViolationException e4) {
DCXError.myInstance().writeError(
"LdapUpdaterConnection:doUpdate SchemaViolationException "+ e4.getExplanation());
DCXError.myInstance().writeError("LdapUpdaterConnection:update persID = " + personId);
return (LdapUpdaterConnection.BAD_DATA);
}
You can't find the exact location only because you haven't logged the stack trace. You would also need to reformat your code so that each statement is on a separate line to make any use of that information. You should also use variable names that actually correspond to the content.
This is really terrible code.
It's also hard to see why you are doing all this in the first place. A decent query filter would do all that for you far more simply.

Categories