I've 3 tables: A, B and C. A holds a one-to- many relation with B and B holds a one-to-one relation with C. When I do a session.save(objA), a row will be created in A, many rows will be created in B referring to the id of A and one row should be created in C for each entry in B referring to the id of B.
Now the problem is, A and B are getting populated as expected, but in C, rows are getting populated but the column containing id of B is populated with null value.
Is it the problem with the mapping given in hbm.xml?
B.hbm.xml
<one-to-one name="propertyC" class="com.model.C"
cascade="all" fetch="join">
</one-to-one>
C.hbm.xml
<many-to-one name="propertyB" class="com.model.B"
column="B_ID" unique ="true" fetch="join" update="true" insert="true" cascade="all">
</many-to-one>
B.java
class B{
private Long id;
private C propertyC;
}
C.java
class C{
private Long id;
private Long bId;
private B propertyB;
}
If you have a oneToOne relation beetween B and C why this is defined like a manyToOne in the C mapping (and not a OneToOne) ?
Furthermore, if you have a bidirectional relationship, you have to define the mappedBy element of the relationship:
#Entity
private static class B {
#Id
private Long id;
#OneToOne
private C propertyC;
}
#Entity
class C {
#Id
private Long id;
private Long bId;
#OneToOne (mappedBy="propertyC")
private B propertyB;
}
Related
I have a table A which has a composite key, say columns A, B and C.
Another table B with some added fields (child of A) will share the primary key A,B,C
Basically when data is inserted in TABLE A, same copy will be there in C with some added information.
Tried Id class , join columns etc.
Sometimes broken id error comes or other .
Please check the structure and let me know if you can help.
Class BIdClass
#Id
#Column(name="A")
private Integer a;
#Id
#Column(name="B")
private Integer b;
#Id
#Column(name="C")
private Integer c;
#Id
#OneToOne(optional=true)
#JoinColumns({
#JoinColumn(name="A", referencedColumnName="A"),
#JoinColumn(name="B", referencedColumnName="B"),
#JoinColumn(name="C", referencedColumnName="C)
})
private ClassA a;
#IdClass
Class B{
#Id
#Column(name="A")
private Integer a;
#Id
#Column(name="B")
private Integer b;
#Id
#Column(name="C")
private Integer c;
#MapsId("a")
#OneToOne
#JoinColumns({
#JoinColumn(name="A", referencedColumnName="A"),
#JoinColumn(name="B", referencedColumnName="B ),
#JoinColumn(name="C", referencedColumnName="C)
})
private ClassA a;
}
Class A{
#OneToOne(mappedBy="a",cascade=CascadeType.ALL)
private ClassB b;
I'm using Spring with hibernate.
The object I'd like to fetch is of class A, which has attribute - a set of object of class B, like
public class A {
private Integer aID;
private Set<B> bs;
private String fieldA1;
private String fieldA2;
// setters and getters
}
public class B {
private Integer bID;
private String fieldB1;
private String fieldB2;
// setters and getters
}
In the mapping file, within the class A mapping tag, I include,
<set name="bs" table="TABLE_B">
<key column="A_ID" />
<one-to-many class="com.proj.test.B"/>
</set>
Now I want to fetch the A object with the bs inside filtered with criteria that depends on value of fieldB1 and fieldB2. (not to fetch all B objects)
Any suggestions / answers?
Try out the following :
#Query(value = "Select a from A a where a.bs.fieldB1 YOUR_CONDITION")
List<A> findAWithFilteredB();
I have 2 entities O and D with a one to many relationship from O (one) to D (many). The relationship itself has an attribute - count.
What is the best way to model this using hibernate?
What I have currently is another entity OD representing the relationship. It has its own artificial key
The abbreviated version of the entities is as below
#Entity
class O {
#Id
private Long id;
#OneToMany(mappedBy = "o")
private Set<OD> ods;
}
#Entity
class OD {
#Id
private Long id;
#ManyToOne
private O o;
// This is uni-directional reln
#OneToOne
private D d;
private int count;
}
Is this the best way? I do not like the fact that the relationship has its own id, but is there a better way to model this relationship?
You can model the OD as #Embeddable, and change the owning side from #OneToMany to #ElementCollection e.g.
#Entity
public class O {
#Id
private Long id;
#ElementCollection
#CollectionTable( name = "OD")
private Set<OD> ods;
}
#Embeddable
public class OD {
// This is uni-directional reln
#OneToOne
private D d;
private int count;
}
The DDL statements would be almost the same with the distinction that the life-cycle of the OD would always be dependent on the life of its parent object, and would not hold an identity of its own
my problem is that I cannot save my entity because it contains another entity, mapped by a key that is also a part of this table's primary key. The table looks like this:
table C:
+-----+------+
| id_A | id_B |
+-----+------+
..where idA is the primary key of table A with EntityA and idB the primary key of table B with EntityB.
so its basically a n-to-m relation. This is the entity I'm using for table C:
#Entity
public class EntityC {
private long idA;
private EntityB b;
#Id
#Column(name = "id_A")
public long getIdA() {
return idA;
}
#Id
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id_B")
public EntityB getB() {
return b;
}
...setters are here...
}
Please note that id_A is mapped as is (the id), while id_B is mapped as its object representation, EntityB. This is what I want to do with it:
EntityC c = new EntityC();
c.setIdA(123);
c.setB(new EntityB());
em.persist(c);
tx.commit();
em.close();
I want to persist EntityB ONLY IF I can persist EntityC.
on tx.commit() I get this exception: org.hibernate.TransientObjectException: object references an unsaved transient instance
I suppose this happens because part of the primary key, id_B, is not saved. But i set cascading to all so there should be no problem!
Why is this not working?
EDIT:
When I do this:
em.persist(c.getB());
em.persist(c);
it works. But can't Hibernate/JPA do that automatically? I thought that's what cascading is good for.
EDIT2:
added an embeddedId instead of id_A and id_B:
#Embeddable
public class EntityCID implements Serializable {
public long idA;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id_B", referencedColumnName = "id")
public EntryB b;
}
EntityC now looks like:
#Entity
public class EntityC implements Serializable {
private EntityCID id;
...
#EmbeddedId
public void getId() {
return id;
}
}
but I still get the transient object exception if I don't em.persist(c.getId().b); before em.persist(c). Sticking to that, although it is ugly.
#Trein: it is not bidirectional. EntityB code:
#Entity
public class EntityB implements Serializable {
public long id;
public String text;
}
If you think about it what you are seeing makes perfect sense.
EntityC is is the 'owning side' of the relationship C<>B: it defines the JoinColumn and EntityB has the 'mappedBy' attribute.
So on saving C, order of events would normally be:
insert into C/update C
insert into B/update B
Now in your case this causes issues as obviously C can only be saved if B has been persisted first.
In terms of your statement above: I want to persist "EntityB ONLY IF I can persist EntityC." How can this ever be the case?
JPA has a concept of 'Derived Identifiers', which I am not overly familiar with however is defined in the book Pro JPA as occurring when:
When an identifier in one entity includes a foreign key to another
entity, we call it a derived identifier. Because the entity containing
the derived identifier depends upon another entity for its identity,
we call the first the dependent entity. The entity that it depends
upon is the target of a many-to-one or one-toone relationship from the
dependent entity, and is called the parent entity
Now, despite the original advice that you had two #Id attributes defined and this was wrong it would however appear that having an additional #Id on a 1-2-m is in fact valid in JPA 2 for precisely this case.
The book gives a number of ways of dealing with Derived Identifiers however one example given below looks fairly similar to your case. So you may want to investigate further the #MapsId attribute.
#Entity
public class Project {
#EmbeddedId private ProjectId id;
#MapsId("dept")
#ManyToOne
#JoinColumns({
#JoinColumn(name="DEPT_NUM", referencedColumnName="NUM"),
#JoinColumn(name="DEPT_CTRY", referencedColumnName="CTRY")})
private Department department;
// ...
}
#Embeddable
public class ProjectId implements Serializable {
#Column(name="P_NAME")
private String name;
#Embedded
private DeptId dept;
// ...
}
See further:
How do I properly cascade save a one-to-one, bidirectional relationship on primary key in Hibernate 3.6
Is it a bidirectional relationship? I would suggest you to remove #Id getB() and perform the modifications:
#OneToOne(cascade = CascadeType.ALL, mappedBy = "id_B")
#PrimaryKeyJoinColumn(name = "id_B")
public EntityB getB() {
return b;
}
Your entity class must have only one attribute annotated with #Id. Usually when you need this, you create a class that will store both properties and this will act as a Id Class.
You can not pass new Entity() for reference. Because it won't have any values in it(even primary key). So how can hibernate will insert it as foreign key to the table. And cascade will save your parent object if its not saved,no need to call save method for all. But when you passing new object it won't do.
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);