Hibernate non-negative value constraint - java

I have the table, the snippet below.
package test;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
#Entity
#Table(uniqueConstraints = { #UniqueConstraint(columnNames = "code")},
name = "coupons")
public class Coupon implements Serializable {
private static final long serialVersionUID = 5534534530153298987L;
#Id
#GeneratedValue
#Column(name = "id")
private long id;
#Column(name = "available_count")
private Integer availableCount = 1;
public Integer getAvailableCount() {
return availableCount;
}
public void setAvailableCount(Integer availableCount) {
this.availableCount = availableCount;
}
}
How to make constraint to allow for availableCount be only non-negative?

If you need an actual database constraint, and your schema is generated by Hibernate, you can use #Check annotation:
#Entity
#Table(uniqueConstraints = { #UniqueConstraint(columnNames = "code")},
name = "coupons")
#Check(constraints = "available_count >= 0")
public class Coupon implements Serializable { ... }

make use of Hibernate Validator project

You can use #Min.
public class Coupon implements Serializable {
#Min(0)
#Column(name = "available_count")
private Integer availableCount = 1;
}
Min documentation: The value of the field or property must be an integer value greater than or equal to the number in the value element
Check all JPA constaints here
They are valid to be used in Hibernate

The easy way would be to make it like this:
public void setAvailableCount(Integer availableCount) {
if(availableCount < 0){
throw new IllegalArgumentExcpetion("Must be possive value");
}
this.availableCount = availableCount;
}
This won't create a databse constraint.
edit:
If you take use of JPA-Annotations, you can create an #PrePerist-Annotated method:
#PrePersist
public void something(){
if(availableCount < 0){
throw new IllegalArgumentExcpetion("Must be possive value");
}
}
The commit should fail, loading should work.

Related

In Spring Boot, how do you set a (extended) property using extended setters and getters?

I am using Spring Boot, and have the following Entity definitions (abridged):
package com.vw.asa.entities;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.PreUpdate;
import javax.validation.constraints.NotNull;
public abstract class CmsModel extends Model {
#Basic(optional = false)
#NotNull
#Column(name = "is_active")
private short isActive;
public short getIsActive() {
return isActive;
}
public void setIsActive(short isActive) {
this.isActive = isActive;
}
public void setIsActive(String isActive) {
if (isActive.equals("true")) {
this.isActive = IS_TRUE;
} else if (isActive.equals("1")) {
this.isActive = IS_TRUE;
} else {
this.isActive = IS_FALSE;
}
}
}
Then I have several models which extend this 'base' model, following this flavor:
package com.vw.asa.entities.cms;
import com.vw.asa.entities.CmsModel;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
/**
* #author Barry Chapman
*/
#Entity
#Table(name = "cms_extra_questions", schema = "asa")
public class CmsExtraQuestions extends CmsModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
...
}
When I initialize an instance of CmsExtraQuestions as a result of a hibernate query, if I call setActive(true) on the object, it has no effect on the members of that object. When I copy the setters and getters from the CmsModel base class into the CmsExtraQuestions class, it works fine.
$entity = new CmsExtraQuestions();
$entity->setActive(true);
Why does this not set the member properties of the instantiated object when calling the extended setter? If this is normal - is there a way to add these properties and member functions to the base model so that they can be inherited also?
Rookie mistake, I forgot to add #MappedSuperClass to the inherited model, CmsModel. That allows JPA to map the properties from that class as though they were defined in the model that was inheriting that base class.
#MappedSuperClass
public abstract class CmsModel extends Model {
#Basic(optional = false)
#NotNull
#Column(name = "is_active")

#OneToOne or #ManyToOne on 'univ_orientation.dz.Entity.cursusGlobale.Student_idStudent' references an unknown entity: int

I'm working in a web app with Hibernate 5 and SpringMVC, when I worked just with simple tables (without relationships between any tables) everything work okay, update, save, delete..., but if I try to add some relationships between tables, and when I mapped, I got this error :
#OneToOne or #ManyToOne on 'univ_orientation.dz.Entity.cursusGlobale.Student_idStudent' references an unknown entity: int
I had searched to solve this issue, I found out that its a configuration problem, Hibernate doesn't recognize class cursusGlobale as an entity.
My question is why Hibernate doesn't recognize class cursusGlobale as an entity when I work with relationships, but it does if I work just with simple tables without relationships between tables?
package univ_orientation.dz.Entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name="cursusGlobale")
public class cursusGlobale {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="idcursusGlobale")
private int idcursusGlobale;
#Column(name="nbrRedoubler")
private int nbrRedoubler;
#Column(name="nbrDette")
private int nbrDette;
#Column(name="idStudent")
private int idStudent;
#OneToOne( cascade= CascadeType.ALL)
#JoinColumn(name="Student_idStudent")
private int Student_idStudent;
public cursusGlobale() {
}
public cursusGlobale(int nbrRedoubler, int nbrDette, int
student_idStudent) {
super();
this.nbrRedoubler = nbrRedoubler;
this.nbrDette = nbrDette;
idStudent = student_idStudent;
}
public int getIdcursusGlobale() {
return idcursusGlobale;
}
public void setIdcursusGlobale(int idcursusGlobale) {
this.idcursusGlobale = idcursusGlobale;
}
public int getNbrRedoubler() {
return nbrRedoubler;
}
public void setNbrRedoubler(int nbrRedoubler) {
this.nbrRedoubler = nbrRedoubler;
}
public int getNbrDette() {
return nbrDette;
}
public void setNbrDette(int nbrDette) {
this.nbrDette = nbrDette;
}
public int getIdStudent() {
return idStudent;
}
public void setIdStudent(int idStudent) {
this.idStudent = idStudent;
}
}
You have not create a relationship. You are using a java native type int instead of another class Student.
#OneToOne( cascade= CascadeType.ALL)
#JoinColumn(name="Student_idStudent")
private int Student_idStudent;
As the error message clearly says: #OneToOne or #ManyToOne on 'univ_orientation.dz.Entity.cursusGlobale.Student_idStudent' references an unknown entity: int, Student_idStudent is defined as an int, not as an Entity. You will need something more along the lines of
#OneToOne( cascade= CascadeType.ALL)
#JoinColumn(name="Student_idStudent")
private Student student;
Even though it is a class it will be persisted as a Foreign Key to the Student table in the database. This is part of the abstraction provided by JPA.
Reference: JPA Hibernate One-to-One relationship

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: no session or session was closed

I am specifying my entity as follows
package com.drishti.training.dbentity;
import java.util.List;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import com.drishti.dacx.core.framework.ameyoentitytypes.AbstractDBEntity;
/**
*
*/
#Entity
#Table(name = "template")
public class TemplateDBEntity extends AbstractDBEntity {
String template_name, organisationId;
#Column(name = "organisation_id", nullable = false)
public String getOrganisationId() {
return organisationId;
}
public void setOrganisationId(String organisationId) {
this.organisationId = organisationId;
}
private String templateId;
// private List<Integer> listOfTrainingIds;
private List<String> listOfTrainingIds;
#Id
#Column(name = "template_id", nullable = false)
public String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
}
#ElementCollection(targetClass = String.class)
#CollectionTable(name = "template_id_vs_training_id", joinColumns = #JoinColumn(name = "template_id"))
#Column(name = "training_id", nullable = false)
public List<String> getListOfTrainingIds() {
return listOfTrainingIds;
}
public void setListOfTrainingIds(List<String> listOfTrainingIds) {
this.listOfTrainingIds = listOfTrainingIds;
}
#Column(name = "template_name")
public String getName() {
return template_name;
}
public void setName(String name) {
this.template_name = name;
}
}
and
another table is
create table template_id_vs_training_id
(
template_id varchar references template(template_id) on delete cascade,
training_id varchar references training(training_id) on delete cascade,
PRIMARY KEY (template_id,training_id)
);
but when i load the TemplateDBEntity it provides me the above reported error.
LazyInitializationException, as hibernate documentation says:
Indicates an attempt to access not-yet-fetched data outside of a
session context. For example, when an uninitialized proxy or
collection is accessed after the session was closed
The only cause of this exception is listOfTrainingIds property as it's an
#ElementCollection which is Lazy loaded by default, so either :
Make sure that you're accessing listOfTrainingIds property inside a transaction (Your entity can use available session to fetch your collection).
Or make it eager #ElementCollection(fetch = FetchType.EAGER), but be aware that every time your select the entity from the database, your collection will be loaded eagerly as well, even if you don't need it, which can impact performance.
Or use fetch keyword in your hibernate Query (if you're using query to load your entity):
List<TemplateDBEntity> TemplateDBEntitys = session.createQuery(
"select t from TemplateDBEntity t join fetch t.listOfTrainingIds",
TemplateDBEntity.class).getResultList();
Or use #FetchProfile.
// In class...
#FetchProfile(
name = "withListOfTrainingIds",
fetchOverrides = {#FetchProfile.FetchOverride(mode = FetchMode.JOIN, association = "listOfTrainingIds", entity = TemplateDBEntity.class)})
public class TemplateDBEntity extends AbstractDBEntity {
//...
}
// To get your entity
session.enableFetchProfile("withListOfTrainingIds");
System.out.println(session.get(TemplateDBEntity.class, templateId));
session.disableFetchProfile("withListOfTrainingIds");
I prefer the last two options, as hibernate will perform one query to database, even you keep the collection lazy loaded, which is better for performance.

java.sql.SQLException: ORA-00942: table or view does not exist with JPA entityManager.createQuery()

I am using JPA createquery API to fetch the data.
Here is my query data
#PersistenceContext
EntityManager entityManager;
#Override
public List<String> fetchAllReleaseNumbers() {
Query query = entityManager.createQuery("SELECT release FROM ReleaseModel", String.class);
return query.getResultList();
}
and here is my pojo class.
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "dbname.tablenamefromDB")
public class ReleaseModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "dbcolumnname", unique = true, nullable = false)
private String release;
#Column(name = "dbcolumnname")
private String releaseDesc;
#Column(name = "dbcolumnname")
private Integer releaseStatus;
#Column(name = "dbcolumnname")
private Integer releaseMode;
public String getRelease() {
return release;
}
public void setRelease(String release) {
this.release = release;
}
public String getReleaseDesc() {
return releaseDesc;
}
public void setReleaseDesc(String releaseDesc) {
this.releaseDesc = releaseDesc;
}
public Integer getReleaseStatus() {
return releaseStatus;
}
public void setReleaseStatus(Integer releaseStatus) {
this.releaseStatus = releaseStatus;
}
public Integer getReleaseMode() {
return releaseMode;
}
public void setReleaseMode(Integer releaseMode) {
this.releaseMode = releaseMode;
}
}
Though the table exists in db its throwing not exist.Any ideas where I made mistake.
I tried whether any aliases can be given to the table name.
I am using pojo class name only for createQuery.
TIA.
You should specify a schema name by this way
#Table(schema = "dbname", name = "tablenamefromDB")
You have an incorrect mapping:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "dbcolumnname", unique = true, nullable = false)
private String release;
I think String can't be auto generated.
Also all your columns have dbcolumnname name.
The issue was that the schema was not specified in the entity class or the user did not login using proxy. If the user login using a proxy access i.e. userName[schemaName] they do not need to specify schema in the entity class. But if the user login using just the userName, they need to specify the schema in the entity. This is to specify where the table can be found in the database.

Can #TableGenerator save the last used id in the table instead of the next available?

I need to connect to a vendor db and insert customer data. The sequence table used to generate new customer ids stores the last used id (not the next available). I couldn't find anything in the jpa or hibernate docs that would indicate a way to tell hibernate to treat the id in the seq table as last used instead of next available (when using #TableGenerator).
Do I need to write a custom generator that will behave essentially the same as #TableGenerator with the only difference being the way the value in the sequence table is treated?
My Customer entity is defined as follows:
#Entity
public class Customer {
#Id
#TableGenerator(name = "cust_gen", table = "SEQUENCE", pkColumnName = "target",
pkColumnValue = "customer", valueColumnName = "id", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.TABLE, generator = "pat_gen")
public long getCustomer_id() {
return customer_id;
}
public void setCustomer_id(Long id) {
this.customer_id = id;
}
...
}
Thanks!
I had the same problem. Fixed it this way:
Use Hibernate org.hibernate.annotations.GenericGenerator instead of persistance TableGenerator like this:
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import org.hibernate.annotations.GenericGenerator;
#Entity
#Table(name = "name")
public class Name implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "names")
#GenericGenerator(name = "names", strategy = "com.ourpackage.SybaseTableGenerator", parameters = {
#Parameter(name = "table_name", value = "new_key_numbers"),
#Parameter(name = "value_column_name", value = "key_number"),
#Parameter(name = "segment_column_name", value = "name"),
#Parameter(name = "segment_value", value = "names_key") })
#Column(name = "names_id")
private Long id;
And create your own generator (I used name com.ourpackage.SybaseTableGenerator):
import java.io.Serializable;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.enhanced.TableGenerator;
#SuppressWarnings("UnusedDeclaration")
public class SybaseTableGenerator extends TableGenerator {
#Override
public synchronized Serializable generate(SessionImplementor session, Object obj) {
return (Long) super.generate(session, obj) + 1;
}
}
A little bit tricky but it works ;)

Categories

Resources