Joincolumn returns null value - java

I am trying to join a column using the #JoinColumn annotation but my column is always returning a null and I am not sure why.
#Entity
public class Blender implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "blender_id")
private int id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "blender", fetch = FetchType.EAGER)
private List<Ingredients> ingredients;
private Status status;
private String type;
public Blender() {
}
public Blender(List<Ingredients> ingredients) {
this.ingredients = ingredients;
}
public List<Ingredients> getIngredients() {
return ingredients;
}
public void setIngredients(List<Ingredients> ingredients) {
this.ingredients = ingredients;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public int getId() {
return id;
}
#Override
public String toString() {
String result = String.format(
"Blender[id=%d, type=%s, status=%s]%n",id,type,status);
if(ingredients!=null){
for (Ingredients ingredient: ingredients) {
result += String.format(
"ingredients[id=%d,fruit=%s,juice=%s,ice=%s]%n",
ingredient.getId(),
ingredient.getFruit(),
ingredient.getJuice(),
ingredient.getIce());
}
}
return result;
}
}
and Ingredients
#Entity
public class Ingredients implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private int fruit;
private int juice;
private int ice;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(columnDefinition="integer", name = "blender_id")
private Blender blender;
public Ingredients() {
}
public Long getId() {
return id;
}
public int getFruit() {
return fruit;
}
public void setFruit(int fruit) {
this.fruit = fruit;
}
public int getJuice() {
return juice;
}
public void setJuice(int juice) {
this.juice = juice;
}
public int getIce() {
return ice;
}
public void setIce(int ice) {
this.ice = ice;
}
public Blender getBlender() {
return blender;
}
public void setBlender(Blender blender) {
this.blender = blender;
}
#Override
public String toString() {
return "Ingredients{" +
"id=" + id +
", fruit='" + fruit + '\'' +
", juice='" + juice + '\'' +
", ice='" + ice + '\'' +
'}';
}
}
#JoinColumn(columnDefinition="integer", name = "blender_id") is returning null not sure why.

try with just
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "blender_id")
private Blender blender;

#OneToMany(mappedBy = "association", cascade = { CascadeType.ALL })
private List<Company> company;
#ManyToOne
#JoinColumn(name = "association_id")
private Association association;
You can try this pattern.
Read for you.
How to Enable Lazy Loading in Hibernate
Before moving further, it is important to recap the default behavior of lazy loading in case of using hibernate mappings vs annotations.
The default behavior is to load ‘property values eagerly’ and to load ‘collections lazily’. Contrary to what you might remember if you have used plain Hibernate 2 (mapping files) before, where all references (including collections) are loaded eagerly by default. Also note that #OneToMany and #ManyToMany associations are defaulted to LAZY loading; and #OneToOne and #ManyToOne are defaulted to EAGER loading. This is important to remember to avoid any pitfall in future.
To enable lazy loading explicitly you must use "fetch = FetchType.LAZY" on a association which you want to lazy load when you are using hibernate annotations.
An example usage will look like this:
#OneToMany( mappedBy = "category", fetch = FetchType.LAZY ) private Set products; Another attribute parallel to "FetchType.LAZY" is "FetchType.EAGER" which is just opposite to LAZY i.e. it will load association entity as well when owner entity is fetched first time.
How Lazy Loading Works in Hibernate
The simplest way that Hibernate can apply lazy load behavior upon your entities and associations is by providing a proxy implementation of them. Hibernate intercepts calls to the entity by substituting a proxy for it derived from the entity’s class. Where the requested information is missing, it will be loaded from the database before control is ceded to the parent entity’s implementation.
Please note that when the association is represented as a collection class, then a wrapper (essentially a proxy for the collection, rather than for the entities that it contains) is created and substituted for the original collection. When you access this collection proxy then what you get inside returned proxy collection are not proxy entities; rather they are actual entities. You need not to put much pressure on understanding this concept because on runtime it hardly matters.

Related

Returning a lazy loaded entity in the JSON response

I have a problem with my Club entity - I'm using LAZY fetch type and ModelMapper to return my JSON. The problem is that if I use LAZY instead of EAGER what I get as a response of GET /api/players/{id} is:
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: could not initialize proxy
and a screenshot from Postman:
When I debug my controller's action:
#GetMapping("/api/players/{id}")
ResponseEntity<PlayerDto> getPlayer(#PathVariable String id) {
Player foundPlayer = playerInterface.getPlayer(Long.valueOf(id));
PlayerDto playerToDto = convertToDto(foundPlayer);
return ResponseEntity.ok().body(playerToDto);
}
...
private PlayerDto convertToDto(Player player) {
return modelMapper.map(player, PlayerDto.class);
}
it seems like both foundPlayer and playerToDto have the Club like this:
but when I do foundPlayer.getClub().getName() I get a proper name. I know it's probably expected behavior, but I would love to have the Club returned in my response like this (screenshot from the response if EAGER is set):
without having to set the fetch type to EAGER.
My Player entity:
#Entity
public class Player {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;;
#ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.EAGER)
#JsonManagedReference
private Club club;
My Club entity:
#Entity
public class Club {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToMany(mappedBy = "club", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JsonBackReference
private List<Player> players;
getPlayer method from the PlayerService (the one, that the controller calls):
#Override
public Player getPlayer(Long id) {
Optional<Player> foundPlayer = playerRepository.findById(id);
return foundPlayer.orElseThrow(PlayerNotFoundException::new);
}
PlayerToDto:
package pl.ug.kchelstowski.ap.lab06.dto;
import pl.ug.kchelstowski.ap.lab06.domain.Club;
public class PlayerDto {
private Long id;
private String firstName;
private String lastName;
private Club club;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Club getClub() {
return club;
}
public void setClub(Club club) {
this.club = club;
}
}
You're right, this is the expected behavior of lazy loading. It's a good thing, don't set it to eager! Instead of returning a Club #Entity class directly on your response body, you should create a ClubDto and initialize it with another convertToDto method. It's kinda tedious (I like using Mapstruct and Lombok to alleviate that), but it'll induce Hibernate to make all the queries you need.
#Data
public class ClubDto {
private String id;
private String name;
}
#Mapper
public interface ClubMapper {
public ClubDTO mapToDto(Club club);
}
Oops, didn't realize you were already using ModelMapper. I'm not too familiar with that, but it sounds like it will just work if you swap Club for ClubDto.
I have a solution guys, but I'd like to hear from you if it can be done this way, or it is some kind of anti-pattern.
I just simply set the playerToDto's Club to the brandly new fetched Club with the ID of the foundPlayer
#GetMapping("/api/players/{id}")
ResponseEntity<PlayerDto> getPlayer(#PathVariable String id) {
Player foundPlayer = playerInterface.getPlayer(Long.valueOf(id));
PlayerDto playerToDto = convertToDto(foundPlayer);
playerToDto.setClub(clubInterface.getClub(foundPlayer.getClub().getId()));
return ResponseEntity.ok().body(playerToDto);
}
In the end I came up with this:
#GetMapping("/api/players")
ResponseEntity<List<PlayerDto>> getAllPlayers() {
List<PlayerDto> playersList = playerInterface.getAllPlayers().stream().map(this::convertToDto).collect(Collectors.toList());
playersList.forEach(playerInterface::fetchClubToPlayer);
return ResponseEntity.ok().body(playersList);
}
#GetMapping("/api/players/{id}")
ResponseEntity<PlayerDto> getPlayer(#PathVariable String id) {
Player foundPlayer = playerInterface.getPlayer(Long.valueOf(id));
PlayerDto playerToDto = convertToDto(foundPlayer);
playerInterface.fetchClubToPlayer(playerToDto);
return ResponseEntity.ok().body(playerToDto);
}
public PlayerDto fetchClubToPlayer(PlayerDto player) {
if (player.getClub() != null) {
Club club = clubInterface.getClub(player.getClub().getId());
player.setClub(club);
}
return player;
}
is it fine?
I suggest you use #EntityGraph to configure the fetch plan of the resulting method's query. For example, you can declare a method in PlayerRepository to find a Player entity by id, apart from the default findById method, where its Club entity would be fetched eagerly.
public interface PlayerRepository extends JpaRepository<Player, Long>{
...
#EntityGraph(attributePaths = {"club"})
Optional<Player> findWithClubFetchedEagerlyById(LongId);
}
By providing attributePaths, fields that should be fetched eagerly are defined.
If the Club entity should be always fetched eagerly when you call the findById method then there's no need for a separate method, therefore you can annotate the default one with #EntityGraph.
With this solution, the network traversal is minimized because all needed data is fetched at once from a database.

Hibernate 5 and JPA: select table without his children but maintain persistence on save

I have two models: Ordine and DettaglioOrdine.
I would like that, when I save an object of type "Ordine", hibernate also save his child "DettaglioOrdine" (and this works).
But, if I do a select query, the query is very very slow because hibernate retrieve also DettaglioOrdine. So, I would like the "Ordine" object without "DettaglioOrdine" object.
"Ordine" model:
#Entity
#Table(name="ordini")
#NamedQuery(name="Ordine.findAll", query="SELECT o FROM Ordine o")
public class Ordine extends DataObject<Integer> {
private static final long serialVersionUID = 1L;
private Integer id;
[...]
private List<Dettagliordine> dettagliordine;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
//bi-directional many-to-one association to Dettagliordine
#Column(insertable = true, updatable = true)
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="ordine")
public List<Dettagliordine> getDettagliordine() {
return this.dettagliordine;
}
public void setDettagliordine(List<Dettagliordine> dettagliordine) {
this.dettagliordine = dettagliordine;
}
public Dettagliordine addDettagliordine(Dettagliordine dettaglioordine) {
dettaglioordine.setOrdine(this);
this.dettagliordine.add(dettaglioordine);
return dettaglioordine;
}
public Dettagliordine removeDettagliordine(Dettagliordine dettagliordine) {
dettagliordine.setOrdine(null);
this.dettagliordine.remove(dettagliordine);
return dettagliordine;
}
}
DettaglioOrdine Model:
#Entity
#Table(name="dettagliordine")
#NamedQuery(name="Dettagliordine.findAll", query="SELECT d FROM Dettagliordine d")
public class Dettagliordine extends DataObject<Integer> {
private static final long serialVersionUID = 1L;
private Integer id;
[...]
public Dettagliordine() {
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
[...]
//bi-directional many-to-one association to Ordini
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="idOrdine", nullable=false)
public Ordine getOrdine() {
return this.ordine;
}
public void setOrdine(Ordine ordine) {
this.ordine = ordine;
}
}
And this is my query:
SessionFactory sessionFactory = getSessionFactory();
Session session = sessionFactory.getCurrentSession();
List<OrdineDTO> result = null;
try{
String hql = "select d.ordine from Dettagliordine d "
+ "group by d.ordine.id";
Query<Ordine> query = session.createQuery(hql,Ordine.class);
List<Ordine> res = query.getResultList();
result = new OrdineDMO().unmarshall(res);
}catch (DMOException e) {
e.printStackTrace();
}
It is not Hibernate. You have fetch=FetchType.LAZY for dettagliordine. Hibernate doesn't have to fetch the lazy association with the parent.
The problem can be here
result = new OrdineDMO().unmarshall(res);
if the code inside unmarshall() method touches dettagliordine or invoke a method, that differs from get, set methods (like toString() method), Hibernate will fetch dettagliordine association.
You can enable Hibernate logging and debug the code. You will see when fetching actually happens. Also keep in mind, if you debug persistent classes, the debugger can cause invoking of toString() method and the association will be fetched too.
Better to move this line outside session/#Transactional block of code.
result = new OrdineDMO().unmarshall(res);
You will have LazyInitializationExcepton, with any unwanted access to lazy associations.

Hibernate creates two rows instead of one

pals.
I have an issue with Hibernate's JPA implementation. I use spring-boot-starter-data-jpa and PostgreSql v9.
I have two entities with bidirectional connection via OneToMany & ManyToOne:
#Entity
public class ShoppingCart {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "shoppingCart", cascade = {CascadeType.ALL})
private List<Good> goods = new ArrayList<>();
public void addGood(Good good) {
good.setShoppingCart(this);
goods.add(good);
}
public Good removeGood(Good good) {
goods.remove(good);
good.setShoppingCart(null);
return good;
}
public ShoppingCart() {
}
public List<Good> getGoods() {
return goods;
}
public ShoppingCart(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
}
And second entity is
#Entity
public class Good {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cart_id")
#JsonIgnore
private ShoppingCart shoppingCart;
public ShoppingCart getShoppingCart() {
return shoppingCart;
}
public void setShoppingCart(ShoppingCart shoppingCart) {
this.shoppingCart = shoppingCart;
}
public Good(String name) {
this.name = name;
}
public Good() {
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
}
Also I use CrudRepository to access ShoppingCart
public interface ShoppingCartRepository extends CrudRepository<ShoppingCart, Long> {}
And when I'm trying to fill existing cart I have two goods in my database. This is a code to add some goods into existing cart:
ShoppingCart cart = shoppingCartRepository.findOne(id);
cart.addGood(new Good("Butter"));
return shoppingCartRepository.save(cart);
In table "good" I have now two elements with different PKey and same data
5;"Butter";100
6;"Butter";100
Why it happens?
Also, when I'm trying to insert breakpoint at repository.save line, I see only one good in goods list in cart.
So, the problem is solved.
First way to solve is to make method with save code #Transactional.
Secon way is to use getGoods() instead of goods. We should change this code
public void addGood(Good good) {
good.setShoppingCart(this);
goods.add(good);
}
public Good removeGood(Good good) {
goods.remove(good);
good.setShoppingCart(null);
return good;
}
to this
public void addGood(Good good) {
good.setShoppingCart(this);
this.getGoods().add(good);
}
public Good removeGood(Good good) {
this.getGoods().remove(good);
good.setShoppingCart(null);
return good;
}
getGoods() here forces hibernate to update state of object and everything works fine.
As for me, I use both ways together
It happens because you create a new Good object without id. So Hibernate will generate a new id and persist the new object. If you don't want to create a new object, but only assign an already existing one, you either have to fetch the existing one from the database and assign it to the ShoppingCart oder add the ID if you create the new Good object.

JpaRepository findOne(id) returns null

This is my first post here, I've been searching for a long time here but I didn't found a problem that seemed similar.
When I use JpaRepository function findOne(id) for one of my classes, it returns null. As if no row had been found for this id.
Of course the database row with this id exists.
Also my class mapping seems right.
I don't understand because I already used findOne() for other classes and I never had any problem.
Anyone can tell me what can be the source of this problem, please ? That would be nice !
This is my DAO :
#Transactional
public interface OrderDetailDAO extends JpaRepository<OrderDetail, Integer>
{
}
This is my Model :
#Entity
#Table(name = "order_detail", schema = "", catalog = AppConfig.databaseSchema)
public class OrderDetail implements Serializable {
private int idOrderDetail;
private Order order;
private Preorder preorder;
private UnitType unitType;
private Sale sale;
private DeliveryStatusType deliveryStatusType;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_Order_Detail")
public int getIdOrderDetail() {
return idOrderDetail;
}
public void setIdOrderDetail(int idOrderDetail) {
this.idOrderDetail = idOrderDetail;
}
#ManyToOne
#JoinColumn(name = "id_Order", referencedColumnName = "id_Order", nullable = false)
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
#ManyToOne
#JoinColumn(name = "id_Preorder", referencedColumnName = "id_Preorder", nullable = false)
public Preorder getPreorder() {
return preorder;
}
public void setPreorder(Preorder preorder) {
this.preorder = preorder;
}
#ManyToOne
#JoinColumn(name = "id_Unit_Type", referencedColumnName = "id_Unit_Type")
public UnitType getUnitType() {
return unitType;
}
public void setUnitType(UnitType unitType) {
this.unitType = unitType;
}
#ManyToOne
#JoinColumn(name = "id_Sale", referencedColumnName = "id_Sale")
public Sale getSale() {
return sale;
}
public void setSale(Sale sale) {
this.sale = sale;
}
#ManyToOne
#JoinColumn(name = "id_Delivery_Status_Type", referencedColumnName = "id_Delivery_Status_Type")
public DeliveryStatusType getDeliveryStatusType() {
return deliveryStatusType;
}
public void setDeliveryStatusType(DeliveryStatusType deliveryStatusType) {
this.deliveryStatusType = deliveryStatusType;
}
}
When I write a request manually, like this :
#Query("SELECT o FROM OrderDetail o WHERE o.idOrderDetail = :idOrderDetail")
public OrderDetail findOneCustom(#Param("idOrderDetail") Integer idOrderDetail);
That works, but that's ugly so I would prefer to use JpaRepository native function findOne()
After all investigation, I have found an interesting answer that is worked for me. I think it is all about defining column type on Db. For my case, I have defined the variable (rid as column) as varchar2(18) that was RID CHAR(18 BYTE).
Java part:
if (dhFlightRepo.findOneFlight(dhFlight.getRid())== null) {
dhFlightRepo.save(dhFlight);
}
If your value that you used as a parameter for findOne() is smallest than set value on column (18 for my case),the jpa doesn't accept value and returns null.You have to change column type as varchar2(18) it can be changeable according to given value on findOne() and work perfect.
I hope that works for all of you.I kindly request to give more detail If someone knows the reason with more detail.

Is this correct (better) object relational mapping?

I have really got stuck with using Hibernate in my project. Some issues I have described here: Hibernate: getting too many rows I have started wondering if my code is correct. I am working on a huge project and I have had to define mapping classes with annotations on my own. But when the problems have began to occur I have decided to recreate part of database separate to the project and try to generate entities in IDE.
I have two tables: My and Option. My has primary key: column qwerty and property. Propertyis the foreign key from Option table. And of course Option has property as a primary key.
In my solution I have created #Embeddable MyPK class with two properties: String qwerty and String property. In my My entity I have of course #EmbeddedId MyPK and also property (the same column name as in the MyPK) but is this Option object, not String as in the MyPK.
#ManyToOne
#JoinColumn(name = "property", nullable = false, insertable = false, updatable = false)
protected Option option;
This is entity generated by Hibernate Tools in Intellij Idea. There isn't EmbeddedId, but there is #IdClass. I have thought that #IdClass is only for basic types. But I have a object as a part of my primary key. However there is also OptionEntity object here. Is this correct to keep basic type and object type for one column?
#javax.persistence.IdClass(test.go.MyEntityPK.class)
#javax.persistence.Table(name = "MY", schema = "PUBLIC", catalog = "PUBLIC")
#Entity
public class MyEntity {
private String qwerty;
#javax.persistence.Column(name = "QWERTY")
#Id
public String getQwerty() {
return qwerty;
}
public void setQwerty(String qwerty) {
this.qwerty = qwerty;
}
private String text;
#javax.persistence.Column(name = "TEXT")
#Basic
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
private String lang;
#javax.persistence.Column(name = "PROPERTY")
#Id
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property= property;
}
#Override
public boolean equals(Object o) {
//equals
}
#Override
public int hashCode() {
//hashCode
}
private OptionEntity optionByProperty;
#ManyToOne
#javax.persistence.JoinColumn(name = "PROPERTY", referencedColumnName = "PROPERTY", nullable = false)
public OptionEntity getOptionByProperty() {
return optionByProperty;
}
public void setOptionByProperty(OptionEntity optionByProperty) {
this.optionByProperty = optionByProperty;
}
}
This is MyEntityPK generated class:
public class MyEntityPK implements Serializable {
private String qwerty;
#Id
#Column(name = "qwerty")
public String getQwerty() {
return qwerty;
}
public void setQwerty(String qwerty) {
this.qwerty = qwerty;
}
private String property;
#Id
#Column(name = "PROPERTY")
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
#Override
public boolean equals(Object o) {
//equals
}
#Override
public int hashCode() {
//hashCode
}
}
OptionEntity below. No special points aren't in this entity. I would like only #Version annotation on version property and also List<MyEntity> instead of Collection<MyEntity>.
#javax.persistence.Table(name = "OPTION", schema = "PUBLIC", catalog = "PUBLIC")
#Entity
public class OptionEntity {
private Long version;
#javax.persistence.Column(name = "VERSION")
#Basic
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
private String property;
#javax.persistence.Column(name = "PROPERTY")
#Id
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
#Override
public boolean equals(Object o) {
//equals
}
#Override
public int hashCode() {
//hashcode
}
private Collection<MyEntity> myByProperty;
#OneToMany(mappedBy = "optionByProperty")
public Collection<MyEntity> getMyByProperty() {
return myByProperty;
}
public void setMyByProperty(Collection<MyEntity> myByProperty) {
this.myByProperty = myByProperty;
}
}
What option is the most proper and less problematic? The one that I have described or the one that pasted?
get rid of property private String lang;/private String property; it is already defined by the manytoone. you also don't need a class for the primary key of MyEntity. MyEntity can be its own id class with the two properties qwerty and option as its key-property, key-manytoone.
Check out JPA 2.0 examples using derived Ids:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/DerivedIdentifiers
which seem to be what you are after.
In JPA, you do not need an embeddedId for your ids, but if using a composite PK, you do need a class to hold the multiple values that make up the pk. Instances of this class are passed to the em.find method, and it can be either an EmbeddedId or a PKClass. I prefer using PKClass myself, but its up to you - using an embedded just places the fields within the embeddedable class, so you use the embedded object to set the mappings and access the values. If using a pkClass, you do not need the fields/properties annotated within it since they are accessed and mapped within the entity directly.

Categories