Map JPA Embedded entity class id to Embeddable entity class id - java

I have a class:
#Entity
public class A {
#Embedded
#AttributeOverride(name = "id", column = #Column(name = "b_id"))
private B b;
}
There is column b_id BIGINT NOT NULL in table A
#Embeddable
#Entity
public class B {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
we are getting error: Caused by: org.hibernate.MappingException: component property not found: id
Basically, we need to map B in A using id
Kindly help

I think the problem is with #Id in embedded class. We can not use in an embedded class. Try removing that? If you can remove it, try using #EmbeddedId if you just need an id field.

Try this
#Entity
public class A implements Serializable {
private static final long serialVersionUID = 9154946919235019012L;
#Embedded
#AttributeOverride(name = "id", column = #Column(name = "b_id"))
private B b;
public A() {
}
public A(B b) {
this.b = b;
}
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
And here is class B
#Embeddable
#Entity
public class B implements Serializable {
private static final long serialVersionUID = 5579181803793008928L;
#Id
#Column(nullable = false)
private Long id;
public B(Long id) {
this.id=id;
}
public B(){
}
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
}
You don't have getters and setters, or an additional constructor besides the implicit no arg one. You should have both a no-args constructor and getter and setter methods.

Related

Understanding Hibernate Junction Table

I have two entities with one to many relationships as below. Everything works fine except delete action. On deleting, I was getting ERROR: relation "a_b" does not exist. For that, I found the solution here.
According to an answer, there was an issue with the relationship and hibernate treats relationships as separate uni-directional relationships and it will create the third table a_b and tracks both sides of the relationship independently. To resolve the issue I had added mappedBy = "a".
Question is
Why does hibernate fires delete query for table a_b while it does not insert into a_b at the time new record creation?
Log on insert
Hibernate: insert into a...
Hibernate: insert into b...
Hibernate: insert into b...
Hibernate: insert into b...
**Why insert into a_b... is not generated/inserted?**
Log on delete
Hibernate: select a0_.id as id1_11_, from a a0_ where (a0_.id in (?))?
Hibernate: delete from b where a_id in (?)
Hibernate: delete from a_b where (a_id) in (select id from a where id in (?))
**Why delete from a_b if nothing is inserted into a_b**
12:19:50.432 [XNIO-1 task-20] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 0, SQLState: 42P01
12:19:50.433 [XNIO-1 task-20] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ERROR: relation "a_b" does not exist
with cause = 'org.hibernate.exception.SQLGrammarException: could not execute statement' and exception = 'could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute statement'
Entity A
#Entity
#Table(name = "a")
public class A extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#OneToMany
private List<B> b;
.....
}
Entity B
#Entity
#Table(name = "b")
public class B extends AbstractAuditingEntity implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#ManyToOne
private A a;
.....
}
AServiceImpl
#Override
public int delete(List<Long> ids) {
...
bRepository.deleteWithIds(ids);
aRepository.deleteWithIds(ids);
}
BRepository
#Transactional
#Modifying
#Query("delete from b x where x.a.id in :ids")
void deleteLogsWithIds(#Param("ids") List<Long> ids);
ARepository
#Modifying
#Transactional
#Query("delete from a x where x.id in :ids")
void deleteJobWithIds(#Param("ids") List<Long> ids);
Current Code
Entity A
#Entity
#Table(name = "a")
public class A extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#OneToMany(mappedBy = "a")
private List<B> b;
.....
}
Entity B
#Entity
#Table(name = "b")
public class B extends AbstractAuditingEntity implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#ManyToOne
private A a;
.....
}
EDIT: Insert sequence
Save Entity A
aRepository.saveAndFlush(a);
Make a call to third party API and based on response set Entity A
for saving Entity B
x.forEach(b-> {
b.setA(aRepository.findById(aId).get());
bRepository.save(b);
});
There can be many scenarios to consider
If you are using a uni-directional oneToMany mapping it will require a join table to save the relationship.Since, a single A entity is associated with multiple B entities and due to its unidirectional nature it does not has a mapping column in B table.enter code here
#Entity
#Table(name = "A")
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
private String stateName;
//This is uni-directional since we donot have a corresponding reference to A in B entity
#OneToMany(cascade = CascadeType.ALL)
List<B> bs = new ArrayList<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<B> getBs() {
return bs;
}
public void setBs(List<B> bs) {
this.bs = bs;
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
}
#Entity
#Table(name="B")
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="ID")
private int id;
private String districtName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDistrictName() {
return districtName;
}
public void setDistrictName(String districtName) {
this.districtName = districtName;
}
}
In the above case its uni-directional oneToMany and it will require a join-table.
If you save your entity like this
enter code here
A a= new A();
B b=new B();
B b1=new B();
List<B> bs=new ArrayList<>();
bs.add(b);
bs.add(b1);
aRepository.save(a);
This will save the relationship mapping in join table.
Case 2:- Now if you add the following in the B entity class it will create a foreign-key column to A table. This will be again a unidirection ManyToOne mapping.
enter code here
#ManyToOne()
A a;
If you the following
enter code here
A a =new A();
B b =new B();
b.setA(a);
B b1=new B();
b1.setA(a);
bRepository.save(b);
bRepository.save(b1);
This will not save the relationship in the join table instead it will use the foreign-key which is present in the table B column named A_ID.
Case 3 :- Bidirectional oneToMany
enter code here
#Entity
#Table(name = "A")
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
private String stateName;
#OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
List<B> bs = new ArrayList<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<B> getBs() {
return bs;
}
public void setBs(List<B> bs) {
this.bs = bs;
}
public void addB(B b) {
b.setA(this);
bs.add(b);
}
public void removeB(B b) {
b.setA(null);
bs.remove(b);
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
}
#Entity
#Table(name = "B")
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
private String districtName;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "A_ID")
A a;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public String getDistrictName() {
return districtName;
}
public void setDistrictName(String districtName) {
this.districtName = districtName;
}
}
The above entity mapping is bi-directional oneToMany and doesn't uses the join-table.

Hibernate: returning null when getting the object in a one to one relation

Whenever I try to get the joined object it is returning null. Sample code below:
Table A
id
name
b_id
Table B
id
name
Coding
#Entity
#Table(name = "A")
public class A {
private Integer id;
#OneToOne
#JoinColumn(name = "b_id", nullable = false)
private B b;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public B getb() {
return b;
}
}
#Entity
#Table(name = "B")
public class B {
private Integer id;
private String name;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public String getname() {
return name;
}
}
When I use getA(id).getB() function it returns null. When I use getA it returns a valid object and not null.
You have to move your #Id and #GeneratedValue(strategy = GenerationType.IDENTITY)
and placed above your id variable like this.
#Entity
#Table(name = "A")
public class A{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToOne
#JoinColumn(name = "b_id", nullable = false)
private B b;
public Integer getId() {
return id;
}
public B getb() {
return b;
}
}
Hope this will help.
May be you should give the FetchType as Eager in the joinColumn annotation to get object B also loaded while a is loaded.
You could consider use more annotation properties, for example:
#OneToOne(cascade = CascadeType.ALL)
#JoinColum(name = "b_id" referencedColumnName = "id", nullable = false)
private B b;
#Entity
#Table(name = "B")
public class B{
**#Column(name="b_id", nullable=false)**
private Integer id;
private String name;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public String getname() {
return name;
}
}
Use #Column(name="b_id", nullable=false)

Java JPA Hibernate save not inserting referenced entities

I have the following 2 classes:
#Entity
#Table(name = "TableA")
public class EntityA
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private final Integer id = null;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "BId")
private EntityB b;
public EntityA(EntityB b)
{
this.b = b;
}
}
#Entity
#Table(name = "TableB")
public class EntityB
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private final Integer id = null;
#OneToOne(mappedBy = "b")
private final EntityA a = null;
}
When I do
session.save(new EntityA(new EntityB());
the database only inserts a record in TableA and leaves the column that references TableB as NULL
If I first insert b, then a, it works, but it should work with a single call too.
Other questions/answers mention that the annotations are not correct, but I see no difference between mine and the provided solutions.
I also tried adding the CascadeType.PERSIST on both #OneToOne annotations, but that didnt work either.
In jpa, default Cascade setting is NONE ... thus the entities in relationships (B in your case) is not inserted (persisted) by default ... You need to annotate the relationship with
#OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.PERSIST)
First of all you must delete final keyword from your entities.
Try this one:
#Entity
#Table(name = "TableA")
class EntityA {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private Integer id;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name = "BId")
private EntityB b;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public EntityB getB() {
return b;
}
public void setB(EntityB b) {
this.b = b;
}
public EntityA(EntityB b) {
this.b = b;
b.setA(this);
}
}
#Entity
#Table(name = "TableB")
class EntityB {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private Integer id;
#OneToOne(mappedBy = "b")
private EntityA a;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public EntityA getA() {
return a;
}
public void setA(EntityA a) {
this.a = a;
}
}
I am using spring boot, hibernate and H2 database
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext app = SpringApplication.run(DemoApplication.class, args);
ServiceCascade bean = app.getBean(ServiceCascade.class);
bean.save();
}
}
#Service
class ServiceCascade {
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void save() {
EntityA entityA = new EntityA(new EntityB());
entityManager.persist(entityA);
}
}
The following logs show that the two entities are inserted correctly
org.hibernate.SQL : insert into tableb (id) values (null)
org.hibernate.SQL : insert into tablea (id, bid) values (null, ?)
o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]

JPA subclass with #IdClass and no attributes

I have a subclass Entity with no #Id or #Column attribute.
but my subclass entity has #IdClass as follows
#Entity
#Table(name = "Employee")
#IdClass(EmployeeEntityPK.class)
public class EmployeeEntity extends AbstractEntity {
#Override
public void setName(String name) {
super.setName(name);
}
#Override
public void setLocation(String location) {
super.setLocation(location);
}
#Override
public void setEmpId(Integer empId) {
super.setEmpId(empId);
}
}
When I try to deploy my project. I am getting exception from hibernate
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547) [rt.jar:1.6.0_17]
at java.util.ArrayList.get(ArrayList.java:322) [rt.jar:1.6.0_17]
at org.hibernate.cfg.AnnotationBinder.getUniqueIdPropertyFromBaseClass(AnnotationBinder.java:2576)
at org.hibernate.cfg.AnnotationBinder.isIdClassPkOfTheAssociatedEntity(AnnotationBinder.java:925)
at org.hibernate.cfg.AnnotationBinder.mapAsIdClass(AnnotationBinder.java:824)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:671)
complete exception is in http://pastebin.com/SnhQ1ZVQ
Hibernate is trying to find #Id class from my Entity which is not there.
How can I resolve this issue.
My super class is as follows
#MappedSuperclass
public class AbstractEntity implements Serializable {
#Id
#Column(name = "empId")
private Integer empId;
#Column(name = "Name")
private String name;
#Column(name = "LOCATION")
private String location;
public Integer getEmpId() {
return empId;
}
//along with other getter setters
}
If I have a primary key with more than one column I use the normal #Id Property on the class I want to use as Pk. The Id-Class is annotated with #Embeddable...
example:
Entity:
#Entity
public class Foo extends AbstractEntity implements Serializable {
private static final long serialVersionUID = 1;
#EmbeddedId
private FooPK id;
//Getter, Setter...
}
EmbeddedId:
#Embeddable
public class FooPK implements Serializable {
private static final long serialVersionUID = 1;
private Integer firstId;
private Integer SecondId;
public FavoritenPK() {
}
// Setter, Getter...
}
EDIT:
I had troubles having the #Id in MappedSuperclass. Try not to put the #Id-Property in Mapped-Superclass!

Wrong query generated with #OrderBy annotation

I am using Hibernate3 and i have an entity with the following collection:
#ManyToMany
#JoinTable(name = "buys_publishers", joinColumns=#JoinColumn(name="buy_id", referencedColumnName = "buy_id"), inverseJoinColumns=#JoinColumn(name = "publisher_id", referencedColumnName = "publisher_id"))
#OrderBy("name")
private List<Publisher> publishers;
(fetch and cascade decelerations omitted)
The target entity (Publisher) inherits from an entity that holds the "name" attribute on which the #orderby is activated.
here is the target entity:
#Entity
#Table(name="publishers")
#PrimaryKeyJoinColumn(name="account_id")
public class Publisher extends Account{
/**
*
*/
private static final long serialVersionUID = 1L;
#Column(name = "publisher_id")
private Long publisherId;
public Long getPublisherId() {
return publisherId;
}
public void setPublisherId(Long publisherId) {
this.publisherId = publisherId;
}
}
and the super class:
#Entity
#Table(name="accounts")
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class Account implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name="id",unique=true, nullable=false )
#GeneratedValue( strategy = IDENTITY )
private long id;
#Column(name = "name")
private String name;
#Column(name = "account_type")
#Enumerated(EnumType.ORDINAL)
private AccountType accountType;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AccountType getAccountType() {
return accountType;
}
public void setAccountType(AccountType accountType) {
this.accountType = accountType;
}
}
the query that Hibernate generates is:
select publishers0_.buy_id as buy1_1_, publishers0_.publisher_id as publisher2_1_, publisher1_.account_id as id6_0_, publisher1_1_.account_type as account2_6_0_, publisher1_1_.name as name6_0_, publisher1_.publisher_id as publisher1_18_0_ from buys_publishers publishers0_ left outer join publishers publisher1_ on publishers0_.publisher_id=publisher1_.publisher_id left outer join accounts publisher1_1_ on publisher1_.account_id=publisher1_1_.id where publishers0_.buy_id=? order by accounts.name asc
it is clear from the query that the order by should be on publisher1_1_, am i doing something wrong or is this a bug?
Thank you.
This looks like HHH-4260 - #OrderBy does not work with inherited properties (and I wouldn't expect a short term resolution).

Categories

Resources