I'm using Spring Data JPA and I'm facing a very weird issue with findOne method which is returning null even though the row is present in DB.
I have a consumer thread which takes an id from a queue and tries to fetch the entity from DB which always returns null, however if I pause thread (by putting a breakpoint before method call) then it fetches the entity from DB but returns null in normal execution of program, I know it sounds weird with breakpoint stuff but it is what it is, may be I'm missing something. My code looks like below:-
if (id > 0) {
employee = employeeService.get(id);
if (employee == null) {
logger.error(String.format("No employee found for id : %d",
id));
return;
}
I'm not using any transaction in "employeeService" as it is not required as it is a read operation.
My service looks like
public Employee get(long id) {
return employeeDao.findOne(id);
}
And my model looks like:-
#Entity
#Table(name = "employee")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Employee implements Serializable {
private static final long serialVersionUID = 1681182382236322985L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "name")
private String name;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "emplopyee_id")
#Fetch(FetchMode.SELECT)
private List<Address> addresses;
// getter/setter and few fields have been omitted
}
Can somebody point me where I'm mistaking.
The Spring 4.2 way to do this would be to introduce a #TransactionEventListener annotated method on a spring component to handle the callback. You then simply need to publish an event and let the event framework do its thing:
// Spring component that handles repository interactions
#Component
public class ProducerService implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Transactional
public void doSomeThingAwesome(String data) {
MyAwesome awesome = new MyAwesome( data );
myAwesomeRepository.save( awesome );
applicationContext.publishEvent( new MyAwesomeSaved( awesome.getId() ) );
}
}
// Spring component that handles the AFTER_COMMIT transaction callback
// This component only fires when a MyAwesomeSaved event is published and
// the associated transaction it is published in commits successfully.
#Component
public class QueueIdentifierHandler {
#TransactionalEventListener
public void onMyAwesomeSaved(MyAwesomeSaved event) {
Long entityId = event.getId();
// post the entityId to your queue now
}
}
Related
Requirement:
To fetch the list of requests along with the requests feedback status.
What I'm doing now :
Fetch all the requests using JPQL query. Loop through each request and fetch status and set into response dto.
What I want to doing.
Fetch all the request along with the status using JPQl query
What I'm looking for :
How can I add one to one mapping for requests & status, so that I can fetch status.
Sample code
This is the MSREQUEST entity
#Entity
#Table(name = "MSREQUEST")
public class Request implements Serializable {
#Id
private long requestId;
#Column(name = "DESC")
private string desc;
//getter.. setter...tostring and hashcode
}
This is the status entity
#Entity
#Table(name="FEEDBACKSTATUS")
public class FeedbackStatus implements Serializable {
// composite-id key
#EmbeddedId
private RequestFeedBackId requestFeedbackKey = new RequestFeedBackId();
#Column(name="STATUS")
private Long status;
//getter.. setter...tostring and hashcode
}
This is the embeddable entity
#Embeddable
public class RequestFeedBackId implements Serializable {
#Column(name="REQUESTID")
private Long requestId;
#Column(name="FEEDBACKID")
private Long feedbackId;
}
Service
#Override
public List<MsaRequestSearchDto> searchMsaRequests(MsaRequestSearchDto msaRequestSearchDto)
throws MsaException, Exception {
List<MsaRequestSearchDto> msaRequestSearchDtoList = msaRequestRepoCustom.findMsaRequests(msaRequestSearchDto);
*// get feedback status loop thru and fetch status for each one. nee to avoid this
if(msaRequestSearchDtoList != null && msaRequestSearchDtoList.size() > 0){
// code to fetch dstatus
}*/
return msaRequestSearchDtoList;
}
JPQL query that Im using..
public String GET_MSA_REQUEST = "SELECT dsr FROM Request dsr WHERE 1=1";
E-R
I am using Spring Data JPA repositories. I have a Card entity and a Transaction entity. When user perform a transaction with card then i would like to save Card and transaction(purchase/refund) entities both. But when user performs next transaction then i want to save Transaction entity only. My Entities are :
Card Entity
#Entity
#Table(name = "CARD")
public class Card {
#Id
private Long card_id;
public Long getCard_id() {
return card_id;
}
public void setCard_id(Long card_id) {
this.card_id = card_id;
}
private String type;
}
Transaction Entity
#Entity
#Table(name="Transaction")
public class Transaction {
#Id
#SequenceGenerator( name="TRAN_SEQ1", initialValue=5,sequenceName="TRAN_SEQ1", allocationSize=1 )
#GeneratedValue( strategy=GenerationType.SEQUENCE, generator="TRAN_SEQ1")
private long id;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "card_id")
private Card card;
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
}
I have tried with below approach but it throws below exception on save:
Transaction t = new Transaction();
Card c = cardRepository.getOne(123L);
t.setCard(c);
transactionRepository.save(t);
**Exception :
org.hibernate.PersistentObjectException: uninitialized proxy passed to persist()**
I am not sure what I am missing. Can anyone guide me here..
Have you tried to add the reverse relationship?
#Entity
#Table(name = "CARD")
public class Card {
#Id
private Long card_id;
#OneToMany
private List<Transaction> transactions = new ArrayList<>();
// Getters and Setters
}
I am using Spring Boot and Spring Data JPA. I have created one entity as a Spring bean with prototype scope. How to I get the bean for each object to persist in database?
#Entity
#Table(name="sample")
#Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Sample {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
If I don't use the entity as Spring bean then I will use the following code to get the object:
Sample sample = new Sample();
How should I use the object using the Prototype scope bean in Spring Boot?
You dont want to define scope for entity. Entities are not like spring bean.
Spring data uses three important components for persisting into the database.
1) Entity Class - Each table has to be defined its own java object model called entity class.
#Entity
#Table(name="sample")
public class Sample {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name="name") //Column name from the table
private String name;
2) Repo Interface- In Which you can define own implementation of SQL, and it would have save method by default.
public interface SampleRepo extends CrudRepository<Sample,Long>{
List<Sample> findByName(String name);
}
3) Client program:
private SampleRepo s;
//instantiate s using autowired setter/constructor
....
//Select example
List<Sample> sampleList=s.findByName("example");
//Insert example
//Id is auto. So no need to setup explicit value for it.
Sample entity=new Sample();
s.setName("Example");
s.save(entity);
i use spring 3.2, spring data and jpa.
i save an Advertisement object,
after i save message
i try to access message from Advertisement but it's null
#Entity
public class Advertisement implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy="id", cascade={CascadeType.REMOVE}, fetch=FetchType.LAZY)
private Set<Message> messages;
}
#Entity
public class Message implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
private Advertisement advertisement;
}
test unit
Advertisement ads = new Advertisement();
ads = advertisementRepo.save(ads);
assertNotNull(ads);
assertNotNull(ads.getId());
Message message = new Message();
message.setAdvertisement(ads);
message = msgRepo.save(message);
ads = advertisementRepo.findOne(ads.getId());
ads.getMessages(); //return null
why ads.getMessages() don't return messages?
The problem is that bidirectional relationships are not transparently managed by JPA. When manipulating one side of a bidirectional relationship, the application has to ensure that the other side is updated accordingly.
This can easily be done by writing setter methods that update the associated entity as well. For example, when setting the Advertisment of a Message, you can add the Message instance to the collection in Advertisment:
#Entity
public class Message implements Serializable {
...
public void setAdvertisement(Advertisement advertisement) {
this.advertisement = advertisement;
advertisement.getMessages().add(this);
}
}
Try to save the Advertisement after you assign it a new Message collection:
Advertisement ads = new Advertisement();
ads = advertisementRepo.save(ads);
assertNotNull(ads);
assertNotNull(ads.getId());
Message message = new Message();
message.setAdvertisement(ads);
ads.setMessages(new HashSet<Message>());
ads.getMessages().add(message);
ads = advertisementRepo.save(ads);
message = msgRepo.save(message);
ads = advertisementRepo.findOne(ads.getId());
ads.getMessages(); //return null
This is returning null because you are saving the non-owning entity first and then the owning entity. If you save message before ads it should return non-null value.
(SORT OF SOLVED, SEE BELOW)
Hibernate 4.1/Spring/JPA project. I'm using Spring & JPA annotations for transactions support, entity manager injection etc.
What I'm seeing that within the same transaction my #OneToMany lazy-loaded collections dont have session property set, and of course cannot be loaded. If I do 'left join fetch' to force loading I get multiple records that point to the same PersistentBag - obviously this throws 'shared collection' exception.
Here is my setup:
Transaction entity ('transaction' is meant as in financial transaction)
Code:
#Entity
#Table(name = "transactionData")
#Access(AccessType.PROPERTY)
public class TransactionData extends AbstractTransaction implements java.io.Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
#OneToMany(cascade=CascadeType.ALL,targetEntity=Location.class,fetch=FetchType.LAZY)
#JoinColumns(
{
#JoinColumn(name="routecode",referencedColumnName="v_OPERSTAT"),
#JoinColumn(name="cogrp", referencedColumnName="v_COUNTRY")
})
#Transactional
public Collection<Location> getLocations() {
return super.getLocations();
}
public void setLocations(Collection<Location> l) {
super.setLocations(l);
}
}
Base class for Transaction:
Code:
public abstract class AbstractTransaction {
private List<Location> _locations;
#Override
#Transactional
public List<Location> getLocations() {
return _locations;
}
#Override
public void setLocations(List<Location> value) {
_locations = value;
}
}
Transaction entity is linked to Location entity using 2 integer type columns, these cols are not PK on either Transaction or Location entity.
Location entity:
Code:
#Entity
#Table(name = "locations", uniqueConstraints = #UniqueConstraint(columnNames = {
"cogrp", "cugrp", "bogrp", "status", "id" }))
public class Location implements java.io.Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "cogrp", nullable = false)
public int getCogrp() {
return this.cogrp;
}
public void setCogrp(int cogrp) {
this.cogrp = cogrp;
}
#Column(name = "routecode")
public Integer getRoutecode() {
return this.routecode;
}
public void setRoutecode(Integer routecode) {
this.routecode = routecode;
}
}
Transaction entity has 1-to-many relationship to locations, and most Transaction entities will point to the same list of locations.
Now, if I do the following query:
Code:
select distinct t from " + Transaction.class.getName() + " t left join fetch t.locations where " + filterSQL
I get results back, but almost every Transaction entity points to the same PersistentBag of locations - needless to say this causes shared references error.
If I omit left join fetch all entities come back with lazily loaded collections, but none have session property set.
If I do eager loading I only get 2 entities eagerly loaded, the rest are still lazy (I know this is a built-in restriction, any way to override that?)
EDIT:
I have come to believe this is a bug in Hibernate. If your query returns multiple records pointing to the same collection (perfectly valid scenario I might add!) then Hibernate will reuse the same collection when eagerly fetching, and set session to null when lazy loading. It will always result in either shared reference to same collection, or 'no session' errors.
I have switched to EclipseLink 2.4, and after fixing my JPSQL it seems to work fine in the above described case.