I have two model in One to One relation, but when t try to save its provide an ID Error,
#Entity
#Table(name = "app_a_table")
class A {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
#OneToOne(mappedBy = "a", cascade = CascadeType.ALL)
private B b;
...
// Constructor
// Getter & Setter
}
#Entity
#Table(name = "app_b_table")
class B {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
#OneToOne()
#JoinColumn(name = "A_ID", referencedColumnName = "ID")
private A a;
...
// Constructor
// Getter & Setter
}
When I tried to save like below
A newA = new A()
B newB = New B()
newB.setProperties().....
newA.setB(newB);
aRepository.save(newA);
An Exception thrown Column 'A_ID' cannot be null
How I can avoid the conflict
Your mapping is bidirectional, thus you also have to maintain it that way:
A newA = new A()
B newB = New B()
newB.setProperties().....
newA.setB(newB);
// add this:
newB.setA(newA);
aRepository.save(newA);
Related
Hi I have 3 entities.
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
...
private List<BC> bcList;
}
#Entity
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
...
}
#Entity
public class C {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
...
}
These entities are linked by ManyToMany associations each other. It means I need an association table which look like a_b_c(id_a,id_b,id_c).
So I've created an AssociationOverrides which work exactly as I want.
#Embeddable
public class ABCPK implements Serializable {
#ManyToOne
#JoinColumn(name = "id_a")
private A a;
#ManyToOne
#JoinColumn(name = "id_b")
private B b;
#ManyToOne
#JoinColumn(name = "id_c")
private C c;
...
}
#Entity
#Table(name = "a_b_c")
#AssociationOverrides({
#AssociationOverride(name = "pk.a",
joinColumns = #JoinColumn(name = "id_a",referencedColumnName = "id")),
#AssociationOverride(name = "pk.b",
joinColumns = #JoinColumn(name = "id_b",referencedColumnName = "id")) ,
#AssociationOverride(name = "pk.c",
joinColumns = #JoinColumn(name = "id_c",referencedColumnName = "id")) })
public class ABC{
#EmbeddedId
private ABCPK pk=new ABCPK();
#Transient
public A getA() {
return pk.getA();
}
public void setA(A a) {
this.pk.setA(a);
}
...
}
public class BC{
private B b;
private List<C> cList;
}
However I would like to retrieve List bcList and List cList from my association table but I really don't know how can I do it. I've already tried #JoinFormula but I prefere to get it working using jpql only. Could you please put me in the right way ?
Thanks
Since I haven't got any help I've made up my mind to populate my map myself and re populate abcList before persist and update . However I really don't like this since it's not performance and memory friendly. (about 1*20*70 items in the abcList)
#Entity
public class A {
...
#OneToMany
private List<ABC> abcList;
private Map<B,List<C>> bcMap;
private Map<B,List<C>> buildBCmap(){
bcMap = new HashMap<>();
if(abcList!=null){
for(ABC abc:abcList){
if(! bcMap.containsKey(abc.getB()){
bcMap.put(abc.getB(),new ArrayList<>());
}
bcMap.get(abc.getB()).add(abc.getC());
}
}
return bcMap;
}
public Map<B,List<C>> getBcMap(){
if(bcMap==null){
buildBCmap();
}
return bcMap;
}
#PrePersist
#PreUpdate
public void buildAbcList(){
if(bcMap!=null){
abcList=new ArrayList<>();
for(B b: bcMap.keySet()){
for(C c: bcMap.get(b)){
abcList.add(new ABC(this,b,c));
}
}
}
}
}
Does anyone have a better or faster way to populate a map from associationOverride entity ?
See code below for my 2 entity classes - when I call the findAll() method from my OrigRepository class, it joins these two tables using both primary keys. I want the join to be between the primary key of the Orig table and the foreign key entry in the MsgResponse table ("OrigID") - any sugggestions?
Orig Entity
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private MsgResponse responseInfo;
}
MsgResponse Entity
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
#Column(name = "OrigID")
private int OrigId;
#OneToOne(mappedBy="responseInfo")
private Orig OrigInfo;
}
I suggest you to see the jpa documentation
here.
Example 1 should be your case
Try to swap relation ownership, that is:
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(mappedBy="origInfo")
private MsgResponse responseInfo;
}
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
// #Column(name = "OrigID")
// private int origId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private Orig origInfo;
}
Note that the #JoinColum annotation is in now in the MsgResponse entity. This is because in a #OneToOne the join column refers to the source entity (see here).
Hope this could help.
Suppose we have entity A that contains a list of entities with type B (with lazy initialization).
Entity B has one BLOB field and some other, that doesn't contain much data.
How can I, using hibernate criteria query, get entity A with it's fields and each A-entity with list of Bs, but every B-entity without the BLOB field ?
Also, I do not want to extract As and iterate them to get Bs. (I now, how to use 'Projections' to extract just Bs with required fields).
Here is some code sample:
A-entity:
#Entity
#Table(name = "A")
public class A implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
#Cascade(CascadeType.ALL)
private List<B> list = new LinkedList<>();
}
B-entity:
#Entity
#Table(name = "B")
public class B implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "data", nullable = false)
#Lob
private byte[] data;
#ManyToOne(targetEntity = A.class, fetch = FetchType.EAGER)
#JoinColumn(name = "A_id", nullable = false)
private A a;
}
I have 3 entities and one entity for linking these three entities:
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "a", fetch = FetchType.LAZY)
private List<ABCXref> abcXref = new ArrayList<ABCXref>();
// getters/setters
}
#Entity
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "b", fetch = FetchType.LAZY)
private List<ABCXref> abcXref = new ArrayList<ABCXref>();
// getters/setters
}
#Entity
public class C {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "c", fetch = FetchType.LAZY)
private List<ABCXref> abcXref = new ArrayList<ABCXref>();
// getters/setters
}
#Entity
public class ABCXref {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JoinColumn(name = "A_ID", nullable = true)
#ManyToOne(optional = true, fetch = FetchType.LAZY)
private A a;
#JoinColumn(name = "B_ID")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private B b;
#JoinColumn(name = "C_ID")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private C c;
}
The question is: does all instances of A, B and C share the same list of ABCXref's? What if I add new ABCXref to A instance? Does this ABCXref appear in list of ABCXrefs of B and C?
I.e. will this code output true?
println(b.getAbcXref().size()); //0
c.getAbcXref().add(new ABCXref(a, b, c));
println(b.getAbcXref().size() == 1) //is `true` or `false`?
I have the following situation:
#Entity
class A{
#Id
#SequenceGenerator(name = "SEQ_AID", sequenceName = "SEQ_AID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_AID")
private Long aId;
#OneToOne(fetch=FecthType.LAZY,optional=false,cascade=CascadeType.ALL)
private B b;
...
}
#Entity
class B{
#Id
private A a;
...
}
In other words: There is a OneToOne association between A and B. B is a weak entity, and its Id is derived from class A.
I've already tested some solutions as adding #PrimaryKeyJoinColumn under #OneToOne as this article mentions. But I got this error: "org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): B"
I don't know if it's relevant in this case, but I'm using Oracle 11g.
UPDATED
I think I'm in the right way. Here is the actual state of my problem:
#Entity
class A{
#Id
#SequenceGenerator(name = "SEQ_AID", sequenceName = "SEQ_AID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_AID")
private Long aId;
#OneToOne(fetch=FecthType.LAZY,optional=false,cascade=CascadeType.ALL)
#PrimaryKeyJoinColumn(name="aId")
private B b;
...
}
#Entity
class B{
#Id
#OneToOne
#JoinColumn(name="aId)
private A a;
...
}
The error now is a bit different:
java.sql.SQLException: ORA-00904: "B"."A": invalid identifier
It is trying to find the column A (instead of AID) in the table B. I don't know how to specify that the column name is B.AID and not B.A.
I solved my problem following this link
The correct answer would be:
#Entity
public class A {
#Id
#GeneratedValue
#Column(name = "aId")
private Long id;
#OneToOne(fetch = FetchType.LAZY, optional=false, cascade = CascadeType.ALL, mappedBy = "a")
private B b;
...
}
#Entity
#org.hibernate.annotations.GenericGenerator(name="a-primarykey", strategy="foreign", parameters={#org.hibernate.annotations.Parameter(name="property", value="a")})
public class B {
#Id
#GeneratedValue(generator = "a-primarykey")
#Column(name = "aId")
private Long id;
#OneToOne
#PrimaryKeyJoinColumn
private A a;
...
}
Have you tried this on Entity B?
#Entity class B {
#Id #OneToOne
#JoinColumn(name = "table_a_id") //put the correct column name for A's pk here
private A a;
....
}