How to define index by several columns in hibernate entity? - java

Morning.
I need to add indexing in hibernate entity. As I know it is possible to do using #Index annotation to specify index for separate column but I need an index for several fields of entity.
I've googled and found jboss annotation #Table, that allows to do this (by specification). But (I don't know why) this functionality doesn't work. May be jboss version is lower than necessary, or maybe I don't understant how to use this annotation, but... complex index is not created.
Why index may not be created?
jboss version 4.2.3.GA
Entity example:
package somepackage;
import org.hibernate.annotations.Index;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
#org.hibernate.annotations.Table(appliesTo = House.TABLE_NAME,
indexes = {
#Index(name = "IDX_XDN_DFN",
columnNames = {House.XDN, House.DFN}
)
}
)
public class House {
public final static String TABLE_NAME = "house";
public final static String XDN = "xdn";
public final static String DFN = "dfn";
#Id
#GeneratedValue
private long Id;
#Column(name = XDN)
private long xdn;
#Column(name = DFN)
private long dfn;
#Column
private String address;
public long getId() {
return Id;
}
public void setId(long id) {
this.Id = id;
}
public long getXdn() {
return xdn;
}
public void setXdn(long xdn) {
this.xdn = xdn;
}
public long getDfn() {
return dfn;
}
public void setDfn(long dfn) {
this.dfn = dfn;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
When jboss/hibernate tries to create table "house" it throws following exception:
Reason: org.hibernate.AnnotationException: #org.hibernate.annotations.Table references an unknown table: house

Please try the following:
#Entity
#org.hibernate.annotations.Table(appliesTo = House.TABLE_NAME,
indexes = {
#Index(name = "IDX_XDN_DFN",
columnNames = {House.XDN, House.DFN}
)
}
)
#Table(name="house")
public class House {
...
}
Note that this should also allow you to create a multi-column index (based on the index name):
#Index(name = "index1")
public String getFoo();
#Index(name = "index1")
public String getBar();
P.S.: What version of Hibernate are you using BTW? What database/dialect?

You have to have hibernate.hbm2ddl.auto set to create in persistence.xml. When set to update hibernate won't create indexes.
hibernate.hbm2ddl.auto = create

You'd better go with a composite primary key.
This article explains how to do it with JPA annotations. It uses #Embeddable and #EmbeddedId

Related

There is an empty array in the http response body if I just return an array of Java Instances in Spring Boot

I return an array of Java Instances in my Spring-Boot-Get-Started project.
package com.wepay.business.resource;
import com.wepay.business.model.Good;
import com.wepay.business.repo.GoodRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
#CrossOrigin(origins = {"http://localhost:3000", "http://localhost:9000", "http://localhost:8083"})
#RestController
#RequestMapping("/api")
public class GoodResource {
#Autowired
GoodRepository repository;
#GetMapping("/getGood")
public List<Good> getAllGoods() {
List<Good> goods = new ArrayList<>();
repository.findAll().forEach(goods::add);
return goods;
}
}
package com.wepay.business.repo;
import com.wepay.business.model.Good;
import org.springframework.data.repository.CrudRepository;
public interface GoodRepository extends CrudRepository<Good, Long> {
}
package com.wepay.business.model;
import javax.persistence.*;
#Entity
#Table(name = "good")
public class Good {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "name")
private String name;
#Column(name = "price")
private double price;
#Column(name = "img")
private String img;
#Column(name = "info")
private String info;
#Column(name = "amount")
private int amount;
#Column(name = "address")
private String address;
#Column(name = "soldAmount")
private String soldAmount;
#Column(name = "sellerId")
private String sellerId;
public Good(){
}
public Good(String name, Double price, String info, int amount) {
this.name = name;
this.price = price;
this.info = info;
this.amount = amount;
}
public Good(Long id, String goodName, Double unitPrice, String goodInfo, int amount) {
this(goodName, unitPrice, goodInfo, amount);
this.id = id;
}
public void setId(Long id) {
this.id = id;
}
}
The value of goods is an array of Java Instacnes
But there is only an empty array in the http response body.
I guess that I should return an array of JSON objects rather than Java Instances.
Do I need to convert the Java Instances to JSON objects? If so, is there any framework to help us to do this job?
I have been blocked by this issue since last week. Thanks in advance.
The problem resides in the fact that your Good class has no getters (atleast by what I see in your post). Add the getters and this should work.
I think you can use JpaRepository<T, ID> instead of CrudRepository<T, ID> so in this case there's no need to instantiate another List<Good>, because the repository.findAll() already returns List<Good> inside the JpaRepository, although by the way you're doing, it should also work normally.
Do I need to convert the Java Instances to JSON objects? If so, is there any framework to help us to do this job?
No. Spring already do it for you by using Jackson's serializer.
try return repository.findAll();
If there is no specific reason to use CrudRepository you can change it to JpaRepository
By doing this you can avoid conversion of Iterator to List and use like this.
public interface GoodRepository extends JpaRepository<Good, Long> {
}
// Controller
#GetMapping("/getGood")
public List<Good> getAllGoods() {
return repository.findAll();
}
Also, Make sure Getter Setter is in place for each persistable field.

Getting entity from table without having primary key in Hibernate

I'm currently working on a project where I'm trying to get a list of enities from table which does not have a primary key (dk_systemtherapie_merkmale). This table is 1:n related to another table (dk_systemtherapie). See the screenshot for the table structure.
When getting an entry for dk_systemtherapie, the program fetches the Collection "dkSystemtherapieMerkmalesById". However, the first table entry is fetched as often as the number of actual entries in the table is. It never fetches the other entries from dk_systemtherapie_merkmale. I assume it has something to do with the fact that hibernate can't differ between the entries, but I don't know how to fix it.
Table schema
I've created two corresponding entity classes, dk_systemtherapie:
#Entity
#Table(name = "dk_systemtherapie", schema = "***", catalog = "")
public class DkSystemtherapieEntity {
private int id;
private Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById;
#Id
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#OneToMany(mappedBy = "dkSystemtherapieByEintragId")
public Collection<DkSystemtherapieMerkmaleEntity> getDkSystemtherapieMerkmalesById() {
return dkSystemtherapieMerkmalesById;
}
public void setDkSystemtherapieMerkmalesById(Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById) {
this.dkSystemtherapieMerkmalesById = dkSystemtherapieMerkmalesById;
}
}
Here the second one, which is accessing the table without a primary key, dk_systhemtherapie_merkmale:
#Entity #IdClass(DkSystemtherapieMerkmaleEntity.class)
#Table(name = "dk_systemtherapie_merkmale", schema = "***", catalog = "")
public class DkSystemtherapieMerkmaleEntity implements Serializable {
#Id private Integer eintragId;
#Id private String feldname;
#Id private String feldwert;
private DkSystemtherapieEntity dkSystemtherapieByEintragId;
#Basic
#Column(name = "eintrag_id")
public Integer getEintragId() {
return eintragId;
}
public void setEintragId(Integer eintragId) {
this.eintragId = eintragId;
}
#Basic
#Column(name = "feldname")
public String getFeldname() {
return feldname;
}
public void setFeldname(String feldname) {
this.feldname = feldname;
}
#Basic
#Column(name = "feldwert")
public String getFeldwert() {
return feldwert;
}
public void setFeldwert(String feldwert) {
this.feldwert = feldwert;
}
#Id
#ManyToOne
#JoinColumn(name = "eintrag_id", referencedColumnName = "id")
public DkSystemtherapieEntity getDkSystemtherapieByEintragId() {
return dkSystemtherapieByEintragId;
}
public void setDkSystemtherapieByEintragId(DkSystemtherapieEntity dkSystemtherapieByEintragId) {
this.dkSystemtherapieByEintragId = dkSystemtherapieByEintragId;
}
}
I assume the problem is releated to the fact that Hibernate is using the following annotation as the one and only id for fetching data from database.
#Id
#ManyToOne
#JoinColumn(name = "eintrag_id", referencedColumnName = "id")
public DkSystemtherapieEntity getDkSystemtherapieByEintragId() {
return dkSystemtherapieByEintragId;
}
This leads to the problem that when getting more than one entry with the same id (as the id is not unique), you will get the number of entries you would like to but hibernate is always fetching the first entry for this id. So in fact you are getting dublicate entries.
So how to fix this?
According to this question: Hibernate and no PK, there are two workarounds which are actually only working when you don't have NULL entries in your table (otherwise the returning object will be NULL as well) and no 1:n relationship. For my understanding, hibernate is not supporting entities on tables without primary key (documentation). To make sure getting the correct results, I would suggest using NativeQuery.
Remove the Annotations and private DkSystemtherapieEntity dkSystemtherapieByEintragId; (incl. beans) from DkSystemtherapieMerkmaleEntity.java und add a constructor.
public class DkSystemtherapieMerkmaleEntity {
private Integer eintragId;
private String feldname;
private String feldwert;
public DkSystemtherapieMerkmaleEntity(Integer eintragId, String feldname, String feldwert) {
this.eintragId = eintragId;
this.feldname = feldname;
this.feldwert = feldwert;
}
public Integer getEintragId() {
return eintragId;
}
public void setEintragId(Integer eintragId) {
this.eintragId = eintragId;
}
public String getFeldname() {
return feldname;
}
public void setFeldname(String feldname) {
this.feldname = feldname;
}
public String getFeldwert() {
return feldwert;
}
public void setFeldwert(String feldwert) {
this.feldwert = feldwert;
}
}
Remove private Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById; (incl. beans) from DkSystemtherapieEntity.java.
Always when you need to get entries for a particular eintrag_id, use the following method instead of the Collection in DkSystemtherapieEntity.java.
public List<DkSystemtherapieMerkmaleEntity> getDkSystemtherapieMerkmaleEntities(int id) {
Transaction tx = session.beginTransaction();
String sql = "SELECT * FROM dk_systemtherapie_merkmale WHERE eintrag_id =:id";
List<Object[]> resultList;
resultList = session.createNativeQuery(sql)
.addScalar("eintrag_id", IntegerType.INSTANCE)
.addScalar("feldname", StringType.INSTANCE)
.addScalar("feldwert", StringType.INSTANCE)
.setParameter("id", id).getResultList();
tx.commit();
List<DkSystemtherapieMerkmaleEntity> merkmale = new ArrayList<>();
for (Object[] o : resultList) {
merkmale.add(new DkSystemtherapieMerkmaleEntity((Integer) o[0], (String) o[1], (String) o[2]));
}
return merkmale;
}
Call getDkSystemtherapieMerkmaleEntities(dkSystemtherapieEntityObject.getid()) instead of getDkSystemtherapieMerkmalesById().

Error in Custome Spring-Jpa

The below query is working fine in mysql.
SELECT * FROM utilization u INNER JOIN sbg s on s.sbg_code=u.sbg_code where u.sbg_code=104
I have written below JPQL query.
#Query("SELECT i FROM Utilization i,i.sbg s where s.sbgCode = :sbgCode")
public ArrayList<Utilization> findUtilization(#Param("sbgCode") int sbgCode);
I am getting below error, please tell how to resolve this error
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: i.sbg is not mapped [SELECT i FROM be.g00glen00b.model.Utilization i,i.sbg s where s.sbgCode = :sbgCode]
Can you please tell me how to write the above sql query to JPQL query?
Please suggest some link to learn JPQL joins because I am new to this.
Below class represents the mapping between two tables
sbg class
#Entity
public class sbg {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int sbgCode;
private String sbgdesc;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="iccode")
#JsonIgnore
private Ic ic;
#OneToMany(mappedBy="sbg1", fetch=FetchType.EAGER)
private List<Utilization> utilization;
public int getSbgCode() {
return sbgCode;
}
public void setSbgCode(int sbgCode) {
this.sbgCode = sbgCode;
}
public String getSbgdesc() {
return sbgdesc;
}
public void setSbgdesc(String sbgdesc) {
this.sbgdesc = sbgdesc;
}
public Ic getIc() {
return ic;
}
public void setIc(Ic ic) {
this.ic = ic;
}
}
utilization class
package be.g00glen00b.model;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
#Entity
public class Utilization {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int asset_type_key;
private String asset_type;
private String Engine_status;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "sbgCode")
private sbg sbg1;
public sbg getSbg1() {
return sbg1;
}
public void setSbg1(sbg sbg1) {
this.sbg1 = sbg1;
}
public int getAsset_type_key() {
return asset_type_key;
}
public void setAsset_type_key(int asset_type_key) {
this.asset_type_key = asset_type_key;
}
public String getAsset_type() {
return asset_type;
}
public void setAsset_type(String asset_type) {
this.asset_type = asset_type;
}
public String getEngine_status() {
return Engine_status;
}
public void setEngine_status(String engine_status) {
Engine_status = engine_status;
}
}
jpa repository
public interface UtilizationRepository extends JpaRepository<Utilization, Integer> {
#Query("SELECT i FROM Utilization i,i.sbg s where s.sbgCode = :sbgCode")
public ArrayList<Utilization> findUtilization(#Param("sbgCode") int sbgCode);
}
You are missing a JOIN in your query.
Your query should look like
SELECT i FROM Utilization i JOIN i.sbg s where s.sbgCode = :sbgCode
When you do queries like this you need to keep in mind that you might get duplicate results back. If you want to get unique results you should use a Set or have a look at this for a way to achieve it with hints and hibernate.

how to make two column as a primary key in hibernate annotation class

This is my annotation class and i want userId and groupId column both as primary key.
I have found more questions (Question) about this, but didn't found relevant answer.
I have less reputation, so I am not able to comment on posts, So I am putting my question here.
This is my code..
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.NaturalId;
#Entity
#Table(name="user_group")
public class user_group {
#Column(name="serviceProvider")
private String serviceProvider;
#Column(name="enterpriseId")
private String enterpriseId;
#Column(name="department")
private String department;
#Column(name="trunkGroupName")
private String trunkGroupName;
#Id
#Column(name="userId")
private String userId;
#Column(name="groupId")
private String group;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getServiceProvider() {
return serviceProvider;
}
public void setServiceProvider(String serviceProvider) {
this.serviceProvider = serviceProvider;
}
public String getEnterpriseId() {
return enterpriseId;
}
public void setEnterpriseId(String enterpriseId) {
this.enterpriseId = enterpriseId;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public String getTrunkGroupName() {
return trunkGroupName;
}
public void setTrunkGroupName(String trunkGroupName) {
this.trunkGroupName = trunkGroupName;
}
}
You should create a new #Embeddable class containing the PK fields:
#Embeddable
public class user_groupId implements Serializable {
#Column(name="userId")
private String userId;
#Column(name="groupId")
private String group;
}
And use it in the #Entity as an #EmbeddedId:
#Entity
public class user_group {
#EmbeddedId
user_groupId id;
...
}
You could also use the #IdClass annotation to that effect.
This excellent answer by Pascal Thivent elaborates on the details. You can also take a look at this other answer I posted to a almost identical question some time ago.
As a side note, if you've got control over the DB structure, you might also consider avoiding composite keys. There are some reasons to do so.
you can create a composite primary key in hibernate using #UniqueConstraint annotation.
#Table(name="user_group",uniqueConstraints=#UniqueConstraint(columnNames= {"userId","groupId"}))
public class user_group
{
#Column(name="userId")
private String userId;
#Column(name="groupId")
private String group;
}
above method is not feasible if we use spring because for creating composite primary key we have to create a class is not a good thing.
in hibernate and spring you only have to create POJO classes which are available as an entity on your system.

Object properties lowercased when reading as JSONObject

I have the following problem. I'm reading a list of records from my MySQL database with Hibernate template, and then I need to modify the structure so I'm JSONObject and JSONArray (using I guess the official library : http://www.json.org/java/). If I'm using the List as a server response, records fields are properly named (thanks to #JsonProperty annotation used). But if I'm trying to create a JSONObject out of this List element, I'm getting all my fields starting with small letter, which breaks my UI.
This is my 'Task' model used :
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
#JsonAutoDetect
#JsonIgnoreProperties(ignoreUnknown = true)
#Entity
#Table(name="tasks")
public class Task {
#Id
#GeneratedValue
#Column(name="Id")
private int Id;
#Column(name="Name", nullable=false)
private String Name;
#JsonProperty("Id")
public int getId() {
return Id;
}
#JsonProperty("Id")
public void setId(int id) {
this.Id = id;
}
#JsonProperty("Name")
public String getName() {
return Name;
}
#JsonProperty("Name")
public void setName(String name) {
this.Name = name;
}
}
and here's the code used for getting records from the DB (stripped of all the unnecessary parts):
public List<Task> getEvents() {
DetachedCriteria criteria = DetachedCriteria.forClass(Task.class);
return hibernateTemplate.findByCriteria(criteria);
}
private static JSONArray read() throws JSONException{
List<Task> list = getEvents();
Iterator<Task> listIterator = list.iterator();
JSONArray ret = new JSONArray();
String parentId;
while(listIterator.hasNext()){
Task task = listIterator.next();
JSONObject taskJSON = new JSONObject(task);
ret.put(taskJSON);
}
}
As you can see in my server response, all fields names start with small letter :
{"id":18,"name":"Release"}
Any ideas how to override this ?
Your class is overannotated, and breaks Java code conventions.
The minimum required is as follows. Everything else you've added is done by default.
#Entity
#Table(name="tasks")
public class Task {
#Id
#GeneratedValue
#Column(name="Id")
#JsonProperty("Id")
private int id;
#Column(name="Name", nullable=false)
#JsonProperty("Name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
To serialise your class all you should need is the ObjectMapper class
String json = new ObjectMapper().writeValueAsString(getEvents());
The output of which should look like:
[{"Id":18,"Name":"Build"}, {"Id":19,"Name":"Release"}]
I would discourage using capitalised property names if possible as it goes against general code conventions.
The JSON.org API is intended for very simple serialization/deserialization, it can't do what your looking for. Having said that, the majority of your annotations are actually from Jackson, which can do what your trying to accomplish.
You already have the POJOs properly annotated for Jackson, so return a JSON string conforming to them, serialize using an ObjectMapper:
final List<Task> list = getEvents();
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(list);

Categories

Resources