Hibernate one to many relation with update child table - java

I have two pojo classes named OwnerDetails & VehicleDetails, which are show below
#Entity
public class OwnerDetails implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="Owner_id")
private int id;
#Column(name="owner_name")
private String ownerName;
#Column(name="email_id")
private String email;
#Column(name="mobile")
private String mobile;
#Column(name="land_line")
private String phone;
#Column(name="Mailing_Address")
private String mailing_address;
#OneToMany(mappedBy="ownerDetails", cascade=CascadeType.ALL)
private Set<VehicleDetails> vehicleDetails;
// getter & Setter...
}
#Entity
public class VehicleDetails implements Serializable{
private static final long serialVersionUID = 1L;
#Id
private int v_id;
#Column(name="TYPE")
private String type;
#Column(name="AC_OR_NON_AC")
private boolean aircondition;
#Column(name="SEATING_CAPACITY")
private int seatingCapacity;
#Column(name="FUEL_TYPE")
private String fuel_type;
#Column(name="Reg_number")
private String reg_number;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="Owner_id")
private OwnerDetails ownerDetails;
// getter & Setter....
}
And the main program is
public static void main(String[] args) throws InterruptedException {
SessionFactory sf=getSessionFactory();
Session session=sf.getCurrentSession();
Transaction txn=session.beginTransaction();
OwnerDetails own=(OwnerDetails)session.get(OwnerDetails.class, 1);
Set<VehicleDetails> vhSet=new HashSet<VehicleDetails>();
VehicleDetails vh=new VehicleDetails();
vh.setAircondition(true);
vh.setFuel_type("DIESEL");
vh.setReg_number("TN32 AA 5555");
vh.setSeatingCapacity(12);
vh.setV_id(11);
vh.setType("INNOVA");
vh.setOwnerDetails(own);
vhSet.add(vh);
own.setVehicleDetails(vhSet);
session.saveOrUpdate(own);
txn.commit();
}
The issue I am having happens after ownerdetails and vehicledetails are saved successfully without any issue.
But I need to add one more vihicledetails with same ownerdetails. It updates current vihicledetails instance with ownerid and existing row in vihicledetails are updated with null ownerid.
please find the below tables.

Looks like the statement own.setVehicleDetails(vhSet); is causing the vehicleDetails set to be replaced with just the new one. Instead use own.getVehicleDetails().add(vh). This will add the new vehicleDetails entity to the existing vehicleDetails set associated with ownerDetails instead of replacing it.

Related

Create a new JPA Entity to produce a new object from two tables

Hello programming council, this is my first use of JPA in anger.
I have 2 Tables:
Entity
#Table(name="category")
public class Category {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name="category")
private String category;
#Column(name="budget")
private double budget;
#Column(name="savings")
private String savings;
#Column(name="archive")
private String archive;
Entity
#Table(name="Transaction")
public class Transaction {
#Id
#Column(name="transaction_no")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long transactionNo;
#Column(name="transaction_date")
private String transactionDate;
#Column(name="transaction_category")
private String transactionCategory;
#Column(name="transaction_description")
private String transactionDescription;
#Column(name="transaction_amount")
private double transcationAmount;
#Column(name="transaction_auto")
private String transactionAuto;
I want to create a new object called Tile which will contain String category and String balance, the SQL for which would be:
select t.transaction_category as category, sum(t.transaction_amount) as balance
from budgeteer.category c
join budgeteer.transaction t
on c.category = t.transaction_category
group by t.transaction_category;
What is the easiest/best way for me to accomplish this?
Thanks in advance.
Ok, so after a little more research, I discovered that I could actually just do this with the same Entity, repository and service without generating a table. You just need to leave out the #Table annotation when you create your entity.

How to correctly fetch data from redis in Java Spring Boot Application

I am having an issue fetching data from redis in my Java spring boot application
I created the following classes
public interface ArticlesRepository extends CrudRepository<Articles, String> {
}
#RedisHash("Articles")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Articles implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private long timestamp;
private ArticlesData articles;
}
#RedisHash("ArticlesData")
#JsonIgnoreProperties(ignoreUnknown = true)
public class ArticlesData implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String continuation;
private ArrayList<ArticleInfo> articles;
}
#RedisHash("ArticleInfo")
#JsonIgnoreProperties(ignoreUnknown = true)
public class ArticleInfo implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String title;
private String linkToArticle;
private long publishedDate;
}
Everything appears to work as expected when I save an instance of Articles
Articles articles = new Articles(id, timestamp, articlesData);
articlesRepository.save(articles);
However, when I attempt to retrieve that object from redis something weird happens
Articles articles = articlesRepository.findOne(redisArticleId);
All the fields in the object (id and timestamp) are set correctly except for ArticlesData which always returns null.
System.out.println(articles.getId()); ==> WAPCO:
System.out.println(articles.getTimestamp()); ==> 1530049920
System.out.println(articles.getArticles()); ==> null
Anyone have any ideas on what I might be doing wrong?

Add multiple Example in criteria (Hibernate)

SchoolViewModel.java
public class SchoolViewModel {
private String state;
private String city;
private String instituteType;
//getter and setter
}
InstituteType.java
#Entity
#Table(name="REF_INSTITUTE_TYPE")
public class InstituteType implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="ID")
private Integer id;
#Column(name="INSTITUTE_TYPE")
private String instituteType;
public Integer getId() {
return id;
}
#ManyToMany(mappedBy="instituteType")
private Set<SchoolDetail> schoolDetail =new HashSet<SchoolDetail>();
//getter and setter
}
Board.java
#Entity
#Table(name="REF_BOARD")
public class Board implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="ID")
private Integer id;
#Column(name="BAORD")
private String board;
#ManyToMany(mappedBy="board")
private Set<SchoolDetail> schoolDetail =new HashSet<SchoolDetail>();
//getter and setter
}
SchoolDetail.java
#Entity
#Table(name="SCHOOL_DETAIL")
public class SchoolDetail implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#Column(name="state")
private String state;
#Column(name="city")
private String city;
#ManyToMany
#JoinTable(name="SCHOOL_INSTITUTE_TYPE",
joinColumns={#JoinColumn(name="SCHOOL_ID")},
inverseJoinColumns={#JoinColumn(name="INSTITUTE_TYPE_ID")}
)
private Set<InstituteType> instituteType=new HashSet<InstituteType>();
#ManyToMany
#JoinTable(name="SCHOOL_BOARD",
joinColumns={#JoinColumn(name="SCHOOL_ID")},
inverseJoinColumns={#JoinColumn(name="BOARD_ID")}
)
private Set<Board> board=new HashSet<Board>();
//getter and setter
}
Main.java
public class SchoolBoard {
public static void main(String[] args) {
Configuration cfg=new Configuration();
cfg.configure("hibernate.cfg.xml");
SessionFactory sessionFactory=cfg.buildSessionFactory();
Session session=sessionFactory.openSession();
try{
SchoolViewModel svm=new SchoolViewModel();
svm.setState("Maharastra");
svm.setCity("Pune");
svm.setInstituteType("college");
SchoolDetail school=new SchoolDetail();
school.setState(svm.getState());
school.setCity(svm.getCity());
InstituteType instituteType=new InstituteType();
instituteType.setInstituteType(svm.getInstituteType());
Board board=new Board();
board.setBoard("STATE");
Example schoolExample=Example.create(school).ignoreCase().enableLike().excludeZeroes();
Example instituteTypeExample=Example.create(instituteType).ignoreCase().enableLike().excludeZeroes();
Example boardExample=Example.create(board).ignoreCase().enableLike().excludeZeroes();
Criteria criteria=session.createCriteria(SchoolDetail.class,"schoolDetail");
criteria.createAlias("schoolDetail.instituteType", "instituteType");
criteria.createAlias("schoolDetail.board", "board");
criteria.add(schoolExample);
criteria.add(instituteTypeExample);
criteria.add(boardExample);
Line - 48 List<SchoolDetail> schoolList=criteria.list();
}finally{
session.close();
sessionFactory.close();
}
}
}
Exception is :
Exception in thread "main" org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private java.util.Set<com.mypack.model.Board> com.mypack.model.SchoolDetail.board] by reflection for persistent property [com.mypack.model.SchoolDetail#board] : com.mypack.model.InstituteType#f555e7
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:71)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getPropertyValues(AbstractEntityTuplizer.java:506)
at org.hibernate.tuple.entity.PojoEntityTuplizer.getPropertyValues(PojoEntityTuplizer.java:215)
at org.hibernate.persister.entity.AbstractEntityPersister.getPropertyValues(AbstractEntityPersister.java:4626)
at org.hibernate.criterion.Example.toSqlString(Example.java:190)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getWhereCondition(CriteriaQueryTranslator.java:400)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:106)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:75)
at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:80)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1849)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:365)
at com.mypack.dao.SchoolBoard.main(SchoolBoard.java:48)
Caused by: java.lang.IllegalArgumentException: Can not set java.util.Set field com.mypack.model.SchoolDetail.board to com.mypack.model.InstituteType
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:387)
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:67)
... 11 more
Description : SchoolViewModel is pojo class which will carry data from front end. The screen is Search screen and contains Refine your search just like any e-commerce website where you can filter or narrow down your search. Based on user selection database will retrieve data from database. For this I have implement query by example in hibernate. But while multiple examples in criteria it throws exception.

queryDSL entity's list contains all

So I have really been struggling to figure this out but there doesn't seem to be good documentation on how to do this. I have an entity RepairMan with a list of Skill entities. I need a query that can return a List<RepairMan> whose list of skills contain all the skill id's. Here is what the entities look like:
#Entity
#Table(name = "REPAIRMAN")
public class RepairMan implements Serializable
{
private static final long serialVersionUID = 8151638047721448259L;
#SequenceGenerator(name="REPAIRMAN_SEQ", sequenceName="REPAIRMAN_SEQ", allocationSize=1, initialValue=100)
#Id #GeneratedValue(generator="REPAIRMAN_SEQ")
private Long id;
#OneToMany
#JoinTable(name="REPAIRMAN_SKILLS", joinColumns=#JoinColumn(name="REPAIRMAN_ID"), inverseJoinColumns=#JoinColumn(name="SKILL_ID"))
private List<Skill> skills;
....
}
#Entity
#Table(name = "SKILL")
public abstract class Skill implements Serializable
{
private static final long serialVersionUID = -5272849377636005084L;
#SequenceGenerator(name="SKILL_SEQ_GEN", sequenceName="SKILL_SEQ", allocationSize=1, initialValue=100)
#Id
#GeneratedValue(generator="SKILL_SEQ_GEN", strategy=GenerationType.SEQUENCE)
private Long id;
#Column(name="NAME")
private String name;
#Column(name="DESCRIPTION")
private String description;
...
}
And here's the desired signature and what I have been able to work out in my mind:
public class RepairManRepositoryImpl extends QueryDslRepositorySupport implements RepairManRepositoryCustom
{
public CompanyInspectorRepositoryImpl()
{
super(RepairMan.class);
}
#Override
public List<RepairMan> getRepairMenByRequiredSkills(List<Long> skillIds)
{
PathBuilder<RepairMan> repairManPath = new PathBuilder<>(RepairMan.class, "repairman");
PathBuilder repairManSkillsPath = repairManPath.get("skills"); // probably wrong
BooleanBuilder hasAllSkills = new BooleanBuilder();
for (Long skillId : skillIds)
{
hasAllSkills.and(repairManSkillsPath.getNumber("id", Long.class).eq(skillId));
}
JPAQuery query = new JPAQuery(getEntityManager())
.from(repairManPath)
//need to join the repairManSkills somehow
.where(hasAllSkills);
return query.list(repairManPath);
}
}
I know this doesn't exactly work, plus I understand it would be easier to use the Qclasses but for compatibility reasons I can't do Qclasses.

I can't get cascade to work on an entity,Hibernate

I have a entity that has two Many-To-One relationships, and one of them cascades on save just fine and the other one returns:
Exception in thread "main" org.hibernate.TransientObjectException: object references an
unsaved transient instance - save the transient instance before flushing : dto.publicSchema.Pessoas
Here is the code of the entity that works:
#Entity
#Table(name="`Doc_tipo`", schema="public")
public class Doc_tipo implements Serializable {
private static final long serialVersionUID = 1859372890916956036L;
#Id
#Column(nullable=false)
private int tp_doc;
#Column(nullable=false,columnDefinition="CHAR(255)")
private String descricao;
#Column(nullable=false,columnDefinition="CHAR(255)")
private String tp_emissor;
//getters and setters
}
And here is the code of the entity that will not allow cascade:
#Entity
#Table(name="`Pessoas`", schema="public")
public class Pessoas implements Serializable {
private static final long serialVersionUID = 8292302132119274975L;
#Id #GeneratedValue
#Column(nullable=false,columnDefinition="serial NOT NULL")
private int seq_pessoa;
static Date padrao_dt_criacao = new Date();
#Column(nullable=false, columnDefinition="date NOT NULL")
private Date dt_criacao = padrao_dt_criacao;
#Column(columnDefinition="CHAR(255)")
private String nome;
#Column(columnDefinition="CHAR(1) NULL")
private char tp_pessoa;
#Column(columnDefinition="CHAR(255)")
private String fantasia;
#Column(columnDefinition="VARCHAR(25)")
private String idioma;
#Column(columnDefinition="VARCHAR(25)")
private String login;
#Column(columnDefinition="VARCHAR(25)")
private String senha;
static Date padrao_dt_i = new Date();
#Column(nullable=false, columnDefinition="date NOT NULL")
private Date dt_i = padrao_dt_i;
//Pessoa está ativa para o sitema se este campo estiver em branco
#Column(columnDefinition="date")
private Date dt_f;
#Column(columnDefinition="oid")
private int foto;
//getters and setters
}
And here is the class that has relationships Many-To-One with the two above
but cascade will only work on the first one:
#Entity
#Table(name="`Documentos`", schema="public")
public class Documentos implements Serializable {
private static final long serialVersionUID = -4874330647877687810L;
#Id
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="seq_pessoa",columnDefinition="integer",referencedColumnName="seq_pessoa",nullable=false)
private Pessoas seq_pessoa;
#Id #GeneratedValue
#Column(nullable=false,columnDefinition="serial NOT NULL")
private int cd_doc;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="tp_doc",referencedColumnName="tp_doc",nullable=false)
private Doc_tipo tp_doc;
#Column(nullable=false)
private int tp_emissor;
#Column(nullable=false,columnDefinition="CHAR(2) NOT NULL DEFAULT 'DF'::bpchar")
private String tp_emissor_uf="DF";
#Column(columnDefinition="CHAR(5)")
private String alfa_doc;
#Column(nullable=false,columnDefinition="CHAR(20)")
private String nr_doc;
//Data de validade do documento
#Column(columnDefinition="date")
private Date dt_f_valid;
#Transient
transient static Date padrao_dt_i = new Date();
#Column(columnDefinition="date DEFAULT now()")
private Date dt_i = padrao_dt_i;
#Column(columnDefinition="date")
private Date dt_f;
//getters and setters
}
When I go to save a Documentos object hibernate inserts the Doc_tipo in to its table
as its supposed to, and instead of inserting the Pessoa object as well throws me that exception.
Here is the class that manipulates the session(it's just for tests):
public class Hibernate {
public static SessionFactory getSessionFactory() {
SessionFactory sessionFactory = null;
try {
Configuration configuration = new Configuration();
configuration.configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(
configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (HibernateException hbe) {
hbe.printStackTrace();
}
return sessionFactory;
}
public static void main(String[] args) {
SessionFactory sessionFactory = getSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Pessoas a = new Pessoas();
a.setDt_criacao(new Date());
a.setDt_f(new Date());
a.setDt_i(new Date());
a.setFantasia("teste");
a.setFoto(12);
a.setIdioma("aa");
a.setLogin("aa");
a.setNome("aa");
a.setSenha("a");
a.setTp_pessoa('H');
Doc_tipo b = new Doc_tipo();
b.setDescricao("aa");
b.setTp_doc(5);
b.setTp_emissor("aaa");
Documentos c = new Documentos();
c.setAlfa_doc("aaa");
c.setDt_f(new Date());
c.setDt_f_valid(new Date());
c.setDt_i(new Date());
c.setNr_doc("aa");
c.setSeq_pessoa(a);
c.setTp_doc(b);
c.setTp_emissor(1);
c.setTp_emissor_uf("aa");
//session.save(a);
session.save(c);
session.getTransaction().commit();
session.close();
}
}
If i remove the comment on the save() Pessoas object, everything works fine, but i shouldn't have to do that, the same exception happens when i try to cascade save in another
entity that has a Many-To-One relationship with Pessoas too.
Documentos references Pessoas with primary key (Pessoas.seq_pessoa) which is only created after it has been saved/flushed to database as Pessoas uses serial. So there is nothing to reference with before save/persist actually happens.
Also, you shouldn't use multiple #Id annotations to define composite identity unless you are also defining #IdClass that holds aforementioned #Id fields. Or you could you #EmbeddedId annotation as well. JPA supports two different approaches for compound PKs. In each case there must be a PK class that includes the fields.
A) Multiple #Id fields/attributes on the entity. Names and types of fields in the entity must match those in the PK class. Must also have an #IdClass annotation on the class. Ex:
public class EmpPK {
int id;
String name;
...
}
#Entity
#IdClass(EmpPK.class)
public class Employee {
#Id int id;
#Id String name;
...
}
B) Embed an attribute of the PK class in the entity. In this case the attribute is marked with #EmbeddedId and the PK class must be annotated with #Embeddable. Ex:
#Embeddable
public class EmpPK {
int id;
String name;
...
}
#Entity
public class Employee {
#EmbeddedId EmpPK empId;
...
}

Categories