#OneTOOne Mapping not save MySQL. JpaRepository - java

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

Java Hibernate map list of list of entities #AssociationOverrides

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 ?

Hibernate/JPA incorrect join in Spring Boot Application

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.

How remove some fields of referenced entity from criteria query in hibernate

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;
}

How works Hibernate #ManyToMany relationship?

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`?

How to map derived identities in hibernate 3?

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;
....
}

Categories