Spring Data JPA repository findAll() method returns null List - spring

I am using Spring Data JPA:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.7.1.RELEASE</version>
</dependency>
with Spring 4.3.7.RELEASE and Hibernate 5.2.9.Final.
When I query using findAll, the List returns contains null values.
Entity:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode
#Entity
public class Etudiant implements Serializable {
/**
* Serial version UID
*/
private static final long serialVersionUID = -1982480763983112005L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idEtudiant")
private Integer idEtudiant;
#Column(name = "nomEtudiant")
private String nomEtudiant;
#Column(name = "prenomEtudiant")
private String prenomEtudiant;
#Column(name = "adresse")
private String adresse;
#Column(name = "dateNaissance")
private Date dateNaissance;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "etudiant_cours", joinColumns = #JoinColumn(name = "idEtudiant", referencedColumnName = "idEtudiant"), inverseJoinColumns =
#JoinColumn(name = "idCours", referencedColumnName = "idCours"))
private List<Cours> cours;
}
NB: Note that the problem is not from lombock, I had tested with getters and setters.
Repository:
#Repository
public interface EtudiantRepository extends JpaRepository<Etudiant, Integer> {
}
Service:
#Service
public class EtudiantServiceImpl {
#Autowired
EtudiantRepository etudiantRepository;
List<Etudiant> lst = new ArrayList<Etudiant>();
public List<Etudiant> getAllEtudiant() {
lst = this.etudiantRepository.findAll();
return lst;
}
}

In debug screenshot, it can be seen that etudiantRepository is null.
Maybe you are missing #EnableJpaRepositories annotation in your Configuration.
EtudiantServiceImpl is being instantiated using Dependency Injection or with the new keyword?

Finally I found the solution :
change spring version from 4.3.7.RELEASE to 4.3.10.RELEASE

you need to use context:component-scan annotation into xml configuration for scanning base package and repository package, you can find code below :
<jpa:repositories base-package="com.demo.test.repository" />
<context:component-scan annotation-config="true"
base-package="com.demo.test" />
and if findall() return null value that means table dose not having data, it is normal behavior.
and also check your datasource and entity manager connection

Related

Spring Boot, Hibernate, bidirectional One-To-Many. Strange behaviour. Why is there two selects insdead of an error?

Spring Boot, Hibernate, bidirectional One-To-Many. Strange behavior. Why is there two selects instead of an error?
I have a basic Spring boot application.
It simulates throwing dices.
I have two entity classes Dice and DiceBatch.
DiceBatch has List<Dice> dices;
Dice has DiceBatch diceBatch; as two sides of bidirectional ManyToOne, or OneToMany.
I use JpaRepository<DiceBatch, UUID> to get one instance of DiceBatch by callig a method of JpaRepository findById(UUID id)
I call this method inside DiceBatchService's method findDiceBatchById(UUID diceBatchId).
Method is marked as #Transactional.
When i do that Hibernate logs one SQL select:
/* select
d
from
DiceBatch d
where
d.id = ?1 */ select
dicebatch0_.dice_batch_id as dice_bat1_1_,
dicebatch0_.batch_creation_time as batch_cr2_1_,
dicebatch0_.batch_name as batch_na3_1_
from
dice_batch dicebatch0_
where
dicebatch0_.dice_batch_id=?
At this point everything is ok.
Method returns DiceBatch entity with lazily initialized List<Dice> dices.
This is important. Method is #Transactional when method returns I should leave transactionla context.
Lazy fields should stay lazy and should cause LazyInitializationException if I try to access them.
Now control goes back to the controller method of DiceBatchController findDiceBatchById(UUID diceBatchId)
And here something strange happens.
Hibernate logs another select
select
dices0_.dice_batch_id as dice_bat5_0_0_,
dices0_.dice_id as dice_id1_0_0_,
dices0_.dice_id as dice_id1_0_1_,
dices0_.dice_batch_id as dice_bat5_0_1_,
dices0_.sequential_number as sequenti2_0_1_,
dices0_.throw_result as throw_re3_0_1_,
dices0_.throw_time as throw_ti4_0_1_
from
dice dices0_
where
dices0_.dice_batch_id=?
...and response JSON contains DiceBatch with all Dice entities related to it.
So I have several question.
Why didn't I get LazyInitializationException?
How come the List<Dice> inside DiceBatch got initialized outside of Transactional context?
How Spring managed to build a complete entity of DiceBatch, including the content of the List<Dice> without any exceptions?
How to modify my code to avoid this strange implicit bahavior?
Here is all the relevant code.
package org.dice.model;
#Entity
#Builder
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Dice {
#Id
#GenericGenerator(name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator")
#GeneratedValue(strategy = javax.persistence.GenerationType.AUTO,
generator = "UUID")
#Column(name = "dice_id",
nullable = false)
private UUID id;
#Column(name = "throw_result",
nullable = false)
private Integer throwResult;
#Column(name = "throw_time",
nullable = false)
private LocalDateTime throwTime;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "dice_batch_id",
nullable = false,
foreignKey = #ForeignKey(name = "fk_dice_dice_batch_id_dice_batch_dice_batch_id")
)
#JsonBackReference
private DiceBatch diceBatch;
#Embedded
private SequentialNumber sequentialNumber;
}
package org.dice.model;
#Entity
#Builder
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class DiceBatch {
#Id
#GenericGenerator(name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator")
#GeneratedValue(strategy = GenerationType.AUTO,
generator = "UUID")
#Column(name = "dice_batch_id",
nullable = false)
private UUID id;
#Column(name = "batch_name",
nullable = false)
private String batchName;
#Column(name = "batch_creation_time",
nullable = false)
private LocalDateTime batchCreationTime;
#OneToMany(
mappedBy = "diceBatch",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY)
#JsonManagedReference
private List<Dice> dices = new ArrayList<>();
public void addDice(Dice dice) {
dices.add(dice);
dice.setDiceBatch(this);
}
public void removeDice(Dice dice) {
dices.remove(dice);
dice.setDiceBatch(null);
}
}
package org.dice.repo;
#Repository
public interface DiceBatchRepo extends JpaRepository<DiceBatch, UUID> {}
package org.dice.service;
#Service
#RequiredArgsConstructor
public class DiceBatchService {
#Transactional
public DiceBatch findDiceBatchById(UUID diceBatchId) {
DiceBatch diceBatch = diceBatchRepo
.findById_my(diceBatchId)
.orElseThrow();
return diceBatch;
}
}
package org.dice.controller;
public class DiceBatchController {
#GetMapping(path = "/get/{diceBatchId}")
public ResponseEntity<DiceBatch> findDiceBatchById(
#PathVariable(name = "diceBatchId") UUID diceBatchId) {
log.info("<C>[/batch/get] endpoint reached.\n" +
"Dice Batch Id: {}\n",
diceBatchId);
return ResponseEntity.ok(diceBatchService.findDiceBatchById(diceBatchId));
}
}

LazyInitializationException when get EAGER fetch object OneToOne

I have two entity
#Entity
#Table(name = "user")
#Data
#Builder
#EqualsAndHashCode(callSuper=false)
#ToString
#AllArgsConstructor
#NoArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "name")
private String name;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#PrimaryKeyJoinColumn
private UserLastLogin userLastLogin;
}
#Entity
#Table(name = "lastLogin")
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
#ToString(onlyExplicitlyIncluded = true)
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class UserLastLogin implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "name")
private String userName;
#Column(name = "date")
private LocalDateTime date;
#OneToOne
#MapsId
#JoinColumn(name = "name")
private User user;
}
I use spring boot with spring data and jpa, hibernate in latest version.
In documentation is that #OneToOne is default EAGER, but when i get eager fetch object, i get lazyInitializationException when i not use #Transactional in get method. I don't understant why...
public UserDto getUser(String userName) {
var user= userRepository.getById(userName);
d.getSystemUserLastLogin(); // this throw lazy initialization exception
return mapper.entityToDto(d);
}
When i'will mark this method #Transactioal, this work. But, not recommendend used transactions in get method. I need use EAGER fetch in this relationship.
When i view query hibernate, i have one select, but children object is not available.
Hibernate:
select
user0_.name as nazwa1_4_0_,
user2_.name as name1_23_2_,
user2_.data as data3_23_2_
from
user0_
left outer join
last_login user2_
on user0_.name=user2_.name
where
user0_.name=?
The problem was that despite the fetch eager, lazy was used. This was due to the use of the getById method from the repository, which retrieves only the object's references and snaps all the fields when lazy is retrieved. Changing to findById solves the problem as findById takes an object, not a reference.
I would recommend you to use secondary tables instead like this:
#Entity
#Table(name = "user")
#Data
#Builder
#EqualsAndHashCode(callSuper=false)
#ToString
#AllArgsConstructor
#NoArgsConstructor
#SecondaryTable(name = "lastLogin", pkJoinColumns = #PrimaryKeyJoinColumn(name = "name"))
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "name")
private String name;
#Column(table = "lastLogin", name = "date")
private LocalDateTime date;
}
Also see https://www.baeldung.com/jpa-mapping-single-entity-to-multiple-tables for more details.

How to use #NamedEntityGraph with #EmbeddedId?

I'm trying to have Spring Data JPA issue one query using joins to eagerly get a graph of entities:
#Entity
#NamedEntityGraph(name = "PositionKey.all",
attributeNodes = {#NamedAttributeNode("positionKey.account"),
#NamedAttributeNode("positionKey.product")
})
#Data
public class Position {
#EmbeddedId
private PositionKey positionKey;
}
#Embeddable
#Data
public class PositionKey implements Serializable {
#ManyToOne
#JoinColumn(name = "accountId")
private Account account;
#ManyToOne
#JoinColumn(name = "productId")
private Product product;
}
Here's my Spring Data repo:
public interface PositionRepository extends JpaRepository<Position, PositionKey> {
#EntityGraph(value = "PositionKey.all", type = EntityGraphType.LOAD)
List<Position> findByPositionKeyAccountIn(Set<Account> accounts);
}
This produces the following exception:
java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [positionKey.account] on this ManagedType
I want all of the accounts and products to be retrieved in one join statement with the positions. How can I do this / reference the embedded ID properties?
I would suggest refactoring the entity this way if it possible
#Entity
#NamedEntityGraph(name = "PositionKey.all",
attributeNodes = {#NamedAttributeNode("account"),
#NamedAttributeNode("product")
})
#Data
public class Position {
#EmbeddedId
private PositionKey positionKey;
#MapsId("accountId")
#ManyToOne
#JoinColumn(name = "accountId")
private Account account;
#MapsId("productId")
#ManyToOne
#JoinColumn(name = "productId")
private Product product;
}
#Embeddable
#Data
public class PositionKey implements Serializable {
#Column(name = "accountId")
private Long accountId;
#Column(name = "productId")
private Long productId;
}
Such an EmbeddedId is much easier to use. For instance, when you are trying to get an entity by id, you do not need to create a complex key containing two entities.

How to make composite Foreign Key part of composite Primary Key with Spring Boot - JPA

I have a problem with the historization of objects in the database.
the expected behavior of the save JpaRepository method is : Insert in the two tables idt_h and abo_h
But the current behavior is Insert in the idt_h table and update in the abo_h table.
#Data
#Entity
#Table(name = "ABO_H")
#AllArgsConstructor
#NoArgsConstructor
public class AboOP {
#Id
#Column(name = "ABO_ID")
private String id;
#Column(name = "ABO_STATUT")
private String statut;
#Column(name = "ABO_DATE_STATUT")
private Instant date;
#Column(name = "ABO_CoDE")
private String code;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "IDC_ID", referencedColumnName = "IDC_ID"),
#JoinColumn(name = "DATE_HISTO", referencedColumnName = "DATE_HISTO")
})
private IdtOP idtOP;
}
#Data
#Entity
#Table(name = "IDT_H")
#AllArgsConstructor
#NoArgsConstructor
public class IdtOP {
#AttributeOverrides({
#AttributeOverride(name = "id",
column = #Column(name = "IDC_ID")),
#AttributeOverride(name = "dateHisto",
column = #Column(name = "DATE_HISTO"))
})
#EmbeddedId
private IdGenerique idtId = new IdGenerique();
//Other fields
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Embeddable
public class IdGenerique implements Serializable {
private String id;
private Instant dateHisto;
}
I think that the class IdGenerique which groups the id and dateHisto is not well invoked for the table abo_h ??
thanks in advance
When you use the save() method, entityManager checks if the entity is new or not. If yes, the entity will be saved, if not, it'll be merged
If you implement your Entity Class with the inteface Persistable, you can override the method isNew() and make it returns True. In that case the save() method will persist, and not merge, your entity.

spring data jpa: No aliases found in result tuple! Make sure your query defines aliases

When I try to get the users using repository interface I received following exception "org.springframework.dao.InvalidDataAccessApiUsageException: No aliases found in result tuple! Make sure your query defines aliases!; nested exception is java.lang.IllegalStateException: No aliases found in result tuple! Make sure your query defines aliases!"
Repository:
#Repository
public interface UserRelationshipRepository
extends JpaRepository<UserRelationship, Long>, QueryDslPredicateExecutor<UserRelationship> {
#Query(value = "SELECT ur.id.toUser FROM UserRelationship ur WHERE ur.fromUser = :fromUser AND ur.relationshipTypeId = 1")
Set<User> findUserFriends(#Param("fromUser") User fromUser);
}
Entities:
#Entity
#NamedEntityGraph(name = "graph.User", attributeNodes = {})
#Table(name = "users")
public class User extends BaseEntity implements UserDetails {
private static final long serialVersionUID = 8884184875433252086L;
#Id
#SequenceGenerator(name = "users_id_seq", sequenceName = "users_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "users_id_seq")
private Long id;
#Column(name = "first_name")
private String firstName;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "fromUser", cascade = CascadeType.ALL)
private Set<UserRelationship> relationships = new HashSet<UserRelationship>();
// getters setters
}
#Entity
#NamedEntityGraph(name = "graph.UserRelationship", attributeNodes = {})
#Table(name = "users_relationships")
public class UserRelationship extends BaseEntity implements Serializable {
private static final long serialVersionUID = -6367981399229734837L;
#EmbeddedId
private final UserRelationshipId id = new UserRelationshipId();
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "from_user_id", nullable = false)
#MapsId("fromUserId") // maps fromUserId attribute of the embedded id
private User fromUser;
#Column(name = "relationship_type_id")
private Long relationshipTypeId;
}
I am using '1.11.0.BUILD-SNAPSHOT' version of spring data jpa.
This is already known issue, and it is marked as resolved, but I am still get it.
Please, help me to solve this.
Update:
If I change repository method's return type to Set<Object> then all works fine.
You're running into DATAJPA-885, which is already fixed and will be part of the Spring Data Hopper SR2 release.

Resources