How to use Hibernate #Index annotation properly? [duplicate] - java

This question already has answers here:
Creating Indexes on DB with Hibernate #Index Annotation
(4 answers)
Closed 7 years ago.
i have a java class used as an entity that has 2 classes that inherit from it. this class has some indices but these indices didn't appear in the database. this is my java super class code
import java.io.Serializable;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;
import javax.persistence.OneToMany;
import org.hibernate.annotations.GenericGenerator;
#Entity
#Table(name="service", uniqueConstraints = {#UniqueConstraint(columnNames={"name"})})
#org.hibernate.annotations.Table(appliesTo = "service",
indexes = { #Index(name = "service_name", columnNames = { "name" }),
#Index(name = "service_description", columnNames = { "description" }),
#Index(name = "service_accessNumber", columnNames = { "access_number" })
})
public class Service implements Serializable {
#Column(name="access_number",length = 95,nullable=false)
String accessNumber;
#Column(length=80,nullable=false)
String name;
#Column(length=140)
String description;
}
does any one know what is my problem
Note: i have this problem in my all java classes but this is one of them. the code in all class is the same of this
Edit: i build an xml file and put it in a grails project, and when i run this project, database created

Would a single #Table annotation work? I haven't tried it, I guess the Hibernate #Table might be overridden by JPA #Table.
You may also try #Index annotation on the column fields:
public class Service implements Serializable {
#Index(name="service_accessnumber")
#Column(name="access_number",length = 95,nullable=false)
String accessNumber;
#Index(name="service_name")
#Column(length=80,nullable=false)
String name;
#Index(name="service_description")
#Column(length=140)
String description;
}

i have the same problem, but i found it's solution and it works fine with me try it, it may help you
in your DataSource.groovy file in your grails project make sure that under
environment dbCreate is not equal to "update": if it is equal to "update", change
it to "create".
This works fine just try it

Related

Spring boot JPA no returning existing result using findById

I have created a pretty small and simple Spring Boot app using the Oracle database and some JPA queries.
This is the code snippet which is not returning data, which is actually exists in database.
letterRecipientNonOas = letterRecipientNonOasRepository
.findById(Long.valueOf(letterRecipientDTO.getNonOas().getId()))
.orElseThrow(() -> new EntityNotFoundException(LetterRecipientNonOas.class,
Constant.MESSAGE_ENTITY_NOT_FOUND));
here findById is returning empty result set.
this is my repository
package com.care.document.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.care.document.model.LetterRecipientNonOas;
/**
* The Interface LetterRecipientNonOasRepository.
*/
#Repository
public interface LetterRecipientNonOasRepository extends PagingAndSortingRepository<LetterRecipientNonOas, Long> {
Optional<LetterRecipientNonOas> findByLetterId(Long id);
Optional<LetterRecipientNonOas> findByTitleIgnoreCase(String title);
List<LetterRecipientNonOas> findByTitleContainingIgnoreCase(String title);
List<LetterRecipientNonOas> findAllByTitleIgnoreCaseAndIdNot(String title, Long recipientId);
List<LetterRecipientNonOas> findAllByIdAndLetterId(long id, long letterId);
}
and this is my model class:
package com.care.document.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import org.springframework.lang.Nullable;
import com.care.admin.model.BaseEntity;
import com.care.admin.util.CommonUtil;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE)
#Entity
#Table(name = "letter_recipient_non_oas")
public class LetterRecipientNonOas extends BaseEntity implements Serializable {
#Id
Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "letter_id")
Letter letter;
Integer recipientType; // Action/Info
//byte recipientSubType; // Internal/External/NonOAS
byte recipientCategory; //Internal/External
int orderNo;
String title;
#Nullable
String remarks;
String address;
#PrePersist
private void prePersist() {
this.id = CommonUtil.generateID(this.atRegion);
}
}
I tested, tried different ways but of no use.
There are a couple of scenarios how one might get this impression:
You are looking at the wrong database.
The data isn't there yet when you try to load it, but is when you check.
JPAs caches are known to create such scenarios rather efficiently.
The data looks a little different than you think. This could be caused by invisible or easy to miss content like spaces or even control characters.
You check the database within the transaction that created the data or with a session that allows dirty reads and the insert that created the data wasn't committed yet.

JPA load entities, but therein in a #OneToMany list, only load specific

Situation:
(using Payara Server)
I have multiple Groups, and each Group has their own specific set of GroupMeetings.
These GroupMeetings are tracked over multiple years.
Each Group contains 100-10000 GroupMeetings.
But usually only the current year's GroupMeetings are queried and used.
Problem:
How can I load all Groups, but only load each Group's GroupMeeting List for a specific interval, for example only the GroupMeetings of 2019? Or, if need be, specific years or ranges, i.e. 2017-2021 etc?
If I simply run a "SELECT *", then with the FetchType.LAZYI will get empty an emtpy List<GroupMeeting>, but as soon as I access it somewhere in the code, all the items will be loaded.
Question:
Whats the best strategy, i.e. somewhat efficient but not overly convoluted?
Is there an easy SQL/JPQL query that I can run with the classes below?
Is there some structural change - especially in the annotations - needed?
Should I consider Criteria API?
Do I have to use two List<GroupMeeting>s, one with the commonly used meetings, the other with the 'old' meetings?
Example:
Here are the two classes:
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
#Entity
public class Group {
#Id //
#GeneratedValue() //
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) #JoinTable(name = "group_meetings") //
private final List<GroupMeeting> meetings = new ArrayList<>();
}
and
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class GroupMeeting {
#Id //
#GeneratedValue() //
private long id;
private String title;
private Date start;
private Date end;
}
You can use Hibernate filters to achieve that, for instance:
#Entity
#FilterDef(name="groupMeetingFilter",
parameters={#ParamDef( name="fromDate", type="date"), #ParamDef(name="toDate", type="date")} )
public class Group {
#Id //
#GeneratedValue() //
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) #JoinTable(name = "group_meetings")
#Filter(
name = "groupMeetingFilter",
condition="start <= :fromDate and end >= :toDate"
)
private final List<GroupMeeting> meetings = new ArrayList<>();
}
And you need to enable your filter somewhere in your application, just like this:
Session session = HibernateUtil.getSessionFactory().openSession();
Filter filter = session.enableFilter("groupMeetingFilter");
//Define here the dates that you want
filter.setParameter("fromDate", new Date());
filter.setParameter("toDate", new Date());
You could go further with your research and make the filter global available, if you're using Spring for instance, is easier.

Hibernate : Genereting dynamic entity at runtime

I need to create entity based on information from database. Based on database I created string like this :
` package az.com.ds.entity.crudEntity;
import javax.persistence.Table;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Column;
#Table(name = "CMN_SP", schema = "CMN")
#Entity
public class CmnSpEnt {
#Id
private Integer id;
#Column(name = "NAME")
private String name;
} `
Then I created java file based on this string and compiled it at runtime. Everything works perfectly to this step. But when I want to get data based on entity it throws exception as
org.hibernate.hql.internal.ast.QuerySyntaxException: CmnSpEnt is not mapped [Select x from CmnSpEnt x ].
Now I need to map entity for hibernate in order to get data from database. Is there a way to accomplish this?

Hibernate : Unable to execute schema management to JDBC target

I'm really stuck here and I need help, I've been trying to run my application and let hibernate create tables using my java entities, but it keeps raising this exception :
Unable to execute schema management to JDBC target [create table answer (id_answer bigint not null auto_increment, order integer, text varchar(255), question_id_question bigint, primary key (id_answer))]
Says that there is an error in my SQL syntax, even though i didn't write any sql, i let hibernate handle it all.
Below are my classes and configuration:
Answer.java :
package com.sfm.elearn.business.entities;
import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity
public class Answer implements Serializable {
#Id #GeneratedValue
private Long idAnswer;
private String text;
private Integer order;
#ManyToOne
#JsonIgnore
private Question question;
public Answer() {
super();
// TODO Auto-generated constructor stub
}
public Answer(String text, Integer order, Question question) {
super();
this.text = text;
this.order = order;
this.question = question;
}
public Long getIdAnswer() {
return idAnswer;
}
public void setIdAnswer(Long idAnswer) {
this.idAnswer = idAnswer;
}
}
This is my configuration :
spring.datasource.url=jdbc:mysql://localhost:3306/ElearningBase
spring.datasource.username=root
spring.datasource.password=654321
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
EDIT: I found the error , the attribute "order" is a reserved SQL keyword that's what was causing the error, changing the variable's name solved it!
If Hibernate is creating your tables for your then your hibernate.ddl-auto property should be set to 'create' or 'create-drop'. The update option means Hibernate expects your tables to already exist. See: Hibernate hbm2ddl.auto possible values and what they do?

Spring Data REST call to `save` receiving object with null variable

I'm continuing the development of a system that uses the React JavaScript library (and related stuff) on the front end and Spring Data REST, Hibernate, PostgreSQL and related stuff on the back end.
This system will be used by people who may own one or more companies and their clients. This means that most/all model objects will have a reference to the Company(ies) that they belong to. Also, company owners will have a few Employees that will have higher level access on this system (or these will be the owners themselves).
I need to implement a functionality where, when a company is inserted in the database, an employee is inserted as well. Also, if one fails, both must fail. Because of how the model was set up, I'm sending an Employee object to be saved, and, within it, the new Company, like this (using Axios):
employee: {
// ...,
company: {
// ....
}
}
Problem is, when the save method is called in the back end, the Company member of the Employee object is null. I've tried a few things, like messing with the relationship, adding an Employee list to the Company object, passing the Company object separately, but nothing worked.
What else could I try? Here are some classes:
Record.java
package xxx.model.common;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;
import lombok.Data;
#Data
#MappedSuperclass
public abstract class Record {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
#NotNull
#Column(name = "deleted")
protected Boolean isDeleted = false;
#NotNull
#Column(name = "enabled")
protected Boolean isEnabled = true;
}
Company.java
package xxx.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import xxx.common.Record;
// ...
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#Entity
#Table(name="company")
#AttributeOverrides( { #AttributeOverride(name = "id", column = #Column(name = "id_company")) } )
public class Company extends Record {
/*
* ...
*/
// Necessary for Hibernate
protected Company() {}
public Company(/* ... */) {
/*
* ...
*/
}
}
Registry.java
package xxx.model.common;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#MappedSuperclass
public abstract class Registry extends Record {
#NotBlank
#Column(name = "code", length = 15)
protected String code;
#NotBlank
#Column(name = "name", length = 40)
protected String name;
}
RegistrySingleCompany.java
package xxx.model.common;
import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import com.fasterxml.jackson.annotation.JsonBackReference;
import xxx.model.Company;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#MappedSuperclass
public class RegistrySingleCompany extends Registry {
#ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE }, optional= false)
#JoinColumn(name="id_company")
protected Company company;
}
Employee.java
package xxx.model;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import xxx.model.common.RegistrySingleCompany;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#Entity
#Table(name="employee")
#AttributeOverrides( { #AttributeOverride(name = "id", column = #Column(name = "id_employee")) } )
public class Employee extends RegistrySingleCompany {
/*
* ...
*/
// Necessary for Hibernate
protected Employee() {}
}
EmployeeRepositoryCustom.java
package xxx.repository.custom;
import org.springframework.data.repository.query.Param;
import xxx.model.Employee;
public interface EmployeeRepositoryCustom {
<S extends Employee> S save(S entity);
}
EmployeeRepositoryCustomImpl.java
package xxx.repository.custom;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestBody;
import xxx.model.Employee;
public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom {
#Override
#Transactional
public <S extends Employee> S save(#RequestBody S entity) {
/*
* ...
*/
return entity;
}
}
EmployeeProjection.java
package xxx.model.projection;
import org.springframework.data.rest.core.config.Projection;
import xxx.model.Employee;
#Projection(name = "employeeProjection", types = { Employee.class })
public interface EmployeeProjection {
Boolean getIsDeleted();
Boolean getIsEnabled();
String getCode();
String getName();
/*
* ...
*/
}
EmployeeRepository.java
package xxx.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import xxx.model.Employee;
import xxx.model.projection.EmployeeProjection;
import xxx.repository.custom.EmployeeRepositoryCustom;
#RepositoryRestResource(collectionResourceRel = "employee", path = "employees", excerptProjection = EmployeeProjection.class)
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>, EmployeeRepositoryCustom {}
Thanks in advance.
Edit: added missing classes.
As mentioned before, one of the things I tried was to add an Employee list inside the Company object, which implies using Company's repository instead of the Employee's one to save both objects, but the other object was also arriving null. However, my colleague found out that, by using exported = false inside #RepositoryRestResource(), the value would be received correctly.
That would screw other things up, so we found the following temporary solution:
Create an exported = false repository (EmployeeWrapper) for the sole purpose of delivering the necessary Employee data to construct a new one inside save.
Instead of adding an Employee list inside Company, add an EmployeeWrapper list.
EmployeeWrapper also references Company.
We're still working on a more correct approach.
Update: a more correct approach:
My colleague also found out that, by adding a #Transient Employee list to Company, it's possible to receive the correctly filled out Employee object to save it. I don't know if it works at the repository since, due to other constraints, we moved to use a #RepositoryRestController and are receiving the Company as #RequestBody org.springframework.hateoas.Resource<Company> resource.
We still want to find a better solution, because an Employee list inside Company wasn't planned in our model and, worse yet, we're needing to use list of other things for other methods.
Update: an even better approach:
Experimenting a little more, we created a POJO containing the entities that we needed and received that in the controller, same way as before. Works well.
We're still not satisfied, though. Ideally, we want to receive the Employee to be saved, with the Company to be saved inside it, and save them both at once.

Categories