I am using hibernate annotations in my application. But I am getting one problem.
class A
#Entity
#Table(name = DBConstants.T_A )
#Inheritance(strategy=InheritanceType.JOINED)
public class A {
//Id
#Column(name = "id")
#GeneratedValue(generator = A_SEQ)
#SequenceGenerator(name = A_SEQ, sequenceName=SeqA_SEQ)
private long id;
....
}
class B
//Entity
#Table(name = "T_B")
#PrimaryKeyJoinColumn(name = "a_id")
public class B extends A{
String a;
.....
}
class C
#Entity
#Table(name = "T_C")
#PrimaryKeyJoinColumn(name = "a_id")
public class C extends B
{
...
}
Initially, I am saving the class A.
After some time, while saving class C, I set Class A id which was saved already. While trying to save the class C, it creates a new class A object and sets that newly created object value to class C object. I needed the class C object with class A object id which is created at first.
I don't understand why a new object of class A is created again. Can anyone please answer to my question what went wrong?
Since you want C to have the same id as an object A that already exists, this is not really entity inheritance.
You basically want a reference to an existing object and you should be using a #OneToOne relationship to map this.
Related
I have strange problem with spring data and inheritance, i have two classes:
#Getter
#Setter
#Entity
#Table(name = "a")
#Inheritance(strategy = InheritanceType.JOINED)
public class A {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "a_id_gen")
#SequenceGenerator(name = "a_id_gen", sequenceName = "a_id_seq", allocationSize = 50)
#Column(name = "id")
private Long id;
}
And class B
#Getter
#Setter
#Entity
#Table(name = "b")
public class B extends A {
#ManyToOne
#JoinColumn(name = "subject")
private Subject subject;
}
Also i have two simple interfaces which extends JpaRepo like this:
public interface ARepository extends JpaRepository<A, Long>
public interface BRepository extends JpaRepository<B, Long>
And then in code in #Transactional i use it like this:
A a = ARepository.findOne(someId);
if (some checks here) {
B b = BRepository.findOne(a.getId());
}
And a problem that B here is NULL, however in DB in table b it exists with same ID 100% sure. IF in debug i write
BRepository.getOne(a.getId());
it returns instance of A, same instance A as above from ARepository.
How i could make this work as i need? I think that problem in some hibernate managed cache or something. I also tried to change equals and hashcode like in this example http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html#identifiers-composite-associations but no luck, problem still there.
Hibernate version is: 5.0.12.Final
Spring boot dependencies: 1.5.6.RELEASE
Ok i found out problem cause. It was query earlier in transaction. JOOK was used to create recursive sql request, and hibernate to map this request to entity. Because of entity have inheritance for mapping i have to add "clazz_" field in request with hard coded 0, after this request all entity was cached in first lvl hibernate cache somehow and cant be then reRequested from DB.
I add to my JOOK
.select(when(B.ID.isNotNull(), 1).otherwise(0).as("clazz_"))
And now all working as expected
I created an instance of A, defined name, with a blank collection of entities B and save it into DB. This is revision #1. Now I use the following statement to get all initial revision of class A
//Get revisions
A a = auditReader.find(A.class, aId, revisions.get(0));
I am getting an exception
could not resolve property: aId_id of: .B_AUDIT [select e__ from B_AUDIT e__ where e__.aId_id = :a_id and e__.originalId.REV.id <= :revision and REVTYPE != :delrevisiontype and (e__.REVEND.id > :revision or e__.REVEND is null)]
Following are my class details
#Table(name = "A")
#Audited
public class A{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
....
#OneToMany(mappedBy = "aId")
#AuditMappedBy(mappedBy = "aId")
private List<B> b;
}
which has #oneToMany relationship with B
#Entity
#Table(name = "B")
#Audited
public class B{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int aId;
...
}
Hibernate Enver Version : 5.1.4.Final
Thank you for your support.
If I had to wager a guess, I believe it is likely because of how you decided to map the oppsite side of the #OneToMany relationship inside entity B. You mapped it directly to the primary key value rather than to the entity type itself.
In other words, Envers likely expected this mapping instead:
#Entity
#Table(name = "B")
#Audited
public class B {
// other stuff removed for breavity
#ManyToOne
private A a;
}
Sorry if my post is duplicated or the tittle doesn't describe the topics, because I don't know how to describe this in the tittle, I look on internet, but I didn't find the solution.
I am using Java and JPA. The problem is the next :
I have a class A with an autogenerated key :
class A{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private List<B> listB;
}
And the class B with the id of this clas:
class B {
#EmbeddedId
private Bid id;
private String att;
}
class Bid {
private int idA;
private String text;
}
In a controller I want to create an object A, the problem is when I created the object A, I need to create the object B where the id of B contains the id of A which is autogenerated, and it is created in the moment when the entity is mapped to de database, I dont't know how to set the id autogenerated of A into the idB, maybe I should query to de database asking what is the las id of classA, but it seem bad.
Thanks in advance
Your case is a derived identifier case, where your entity B's identity was derived from the primary key of A. You can use #MapsId annotation for this case and your entities can be restructured like this:
#Entity
public class A {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#OneToMany(mappedBy="a")
private List<B> listB = new ArrayList<B>();
...
}
#Entity
public class B {
#EmbeddedId
private BId id;
#ManyToOne
#MapsId("idA")
private A a;
...
}
#Embeddable
public class BId {
private int idA;
private String att;
...
}
This is how you would persist the entities:
A a = new A();
BId bid = new BId();
bid.setAtt("text"); // notice that the idA attribute is never manually set, since it is derived from A
B b = new B();
b.setId(bid);
b.setA(a);
a.getListB().add(b);
em.persist(a);
em.persist(b);
See sample implementation here.
It would be useful to know which is the case scenario you are trying to solve in general because the structure you are using seems unnecessarily complex.
What is your real goal?
i want to implement bi-directional One-To-Many relationship in my app engine application. I have two entities - entity A (parent) and entity B(child).
Parent :
#Entity
public class A implements Serializable {
#Id
private String aId;
#OneToMany(mappedBy = "objA", cascade = CascadeType.ALL)
List<B> bList;
getter().........setter()
}
Child :
#Entity
public class B implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key bId;
#ManyToOne(fetch = FetchType.LAZY)
private A parentA;
getter().........setter()
}
Here,at first i persist object of class A and at that time i don't set its bList property. After that i create object of B and update setbList() of A which will automatically persist object of type B in datastore (as here i have set cascade=CascadeType.ALL).Now i want to access A from B objects.(parent from child) in my endpoint class which i am using in my android client. How can i achieve this?
You just need to add a reference to A in your B class
private A parentA;
parentA = //whatever you use when you update setbList()
Good luck!
I have two tables in database, A and B. Table B has an id composed of two fields. One of them is a foreign key to A. Id of A is automatically generated on insert by a sequence.
A:
ID (PK)
(*other fields*)
B:
SOME_FIELD (PK)
A_ID (PK, FK to A)
I have mapped the two tables in JPA (Hibernate) following JPA specification, in this way:
#Entity
#Table(name = "A")
public class A implements Serializable {
#Id
#SequenceGenerator(name = "A_SEQ", sequenceName = "A_SEQ")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "A_SEQ")
#Column(name = "ID")
private Long id;
(...)
}
#Entity
#Table(name = "B")
public class B implements Serializable {
#EmbeddedId
#AttributeOverride(name = "someField", column = #Column(name = SOME_FIELD))
private BPK pk;
#MapsId("aId")
#ManyToOne
#JoinColumn(name = "A_ID")
private A a;
(...)
}
#Embeddable
public class BPK implements Serializable {
private Long aId;
private String someField;
#Override
public boolean equals(Object o) {
(...)
}
#Override
public boolean hashCode() {
(...)
}
(...)
}
The problem is that when I try to save an B object calling entityManager.persist(b), where b.a is set to an A object, which exists already in database, I get an exception:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: package.name.A
I don't know why this happens. I'm trying to save object of class B, not A. Is my entity class wrong? Or maybe I shouldn't use persist here?
It could be that the entity A is no longer being held by entity manager. Have you tried setting B.a with a "fresh" instance of A?
b.setA(get(b.a));
entityManager.persist(b);
The get(b.a) method can be whatever you usually use to find entity A from your datasource e.g. entityManager.getReference(A.class, a.id);