I'd like to create a OneToOne relation between two entities(also tables in mysql). When i get a post request i want to save the A entity and then B entity is saved automatically, because there is a column in B ("a_id") that is foreign key of the primary key in A ("id_a"). How can i map them correctyl?
#Table("a_tb")
public class A(){
#Column(name="id_a")
private Long idA;
#OneToOne(mappedBy = "aId", cascade = CascadeType.ALL,
fetch = FetchType.LAZY, orphanRemoval = true, optional = false)
private B b;
}
#Table("b_tb")
public class B(){
#Column(name="id_b")
private Long idB;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id")
private Long aId;
}
Have tried to set idA to A type, but when i call the get method he will loop calling A with B innested that as A innested and so on..
I just want to save the id of A in B, not the entire object, otherwise he will return the entire object when i call the get method and the loop is back.
The mapping is correct, not the autoset of the value in a_id in B.
What I expect is: when i create A, B gets automatically the id of A and save it to its column ("id_a") in db when i request to save object A. That's should work with delete too (when i delete A, B is deleted too).
The matched JSON will be:
{
"a":{
"id_a": "value",
},
"b":{
"id_b": "value",
"a_id": "id_a"
}
}
Thanks in advice.
from the first look it looks like
#OneToOne
#JoinColumn(name = "idA_id")
A a;
would be the change you need and
You need to provide one to one mapping [Reference] in both the classes.
If parent reference, not setup automatically you can create a transient variable and set parent's primary key using it.
Try this Example:
#Table("a_tb")
public class A(){
#Column(name="id")
private Long id;
#OneToOne(mappedBy = "aId", cascade = CascadeType.ALL,
fetch = FetchType.LAZY, orphanRemoval = true, optional = false)
private B b;
}
#Table("b_tb")
public class B(){
#Column(name="id")
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id")
private A a;
#Transient
private Long aId;
// getters and setters
public void setAId(Long aId){
if(aId != null){
this.a = new A();
this.a.setId(aId);
}
}
}
Related
I have got two entities:
class A{
#Id
private int id;
#OneToMany(fetch = FetchType.LAZY , mappedBy = "a")
private List<B> bList;
}
class B{
#Id
private int id;
#ManyToOne(fetch = FetchType.LAZY, targetEntity=A.class)
#JoinColumn(name = "A_ID", referencedColumnName = "id", nullable = true)
private A a;
}
For example I have got "a" persistent property from B class and I need to retrieve the other side of association - "bList" persistentProperty of A class. But I don't know the name of the other side property. How could I do that? Association obverse property is null every time. And I don't want to use doWithProperties() method and check fields for equality by class, because there are might be some other properties with the same class.
I was trying to make something like this:
PersistentEntities persistentEntities;
Class aClass = A.class;
Class bClass = B.class;
PersistentProperty<?> obverse = persistentEntities.getPersistentEntity(bClass).getPersistentProperty("a").getAssociation().getObverse();
But it is null every time. Maybe I am missing something. Thanks for help!
So nothing I tried seems to work. I would like to have something like this:
class A {
B foo;
B bar;
}
class B {
A baz;
}
What I tried in class A is as follows:
#OneToOne(targetEntity = B.class)
#JoinColumn(name = "foo_id")
#Cascade(CascadeType.ALL)
public B getFoo() {
return foo;
}
#OneToOne(targetEntity = B.class)
#JoinColumn(name = "bar_id")
#Cascade(CascadeType.ALL)
public B getBar() {
return bar;
}
which does not seem to work. I always end up where foo_id and bar_id is same for a reason I do not understand.
So when I inspect table "A" in my DB for row with id 1, I would like to have:
foo_id = 1
bar_id = 2
and in Table B, I should have 2 entities with id 1 and 2, where both have baz_id = 1;
Is baz_id intended to be a FK back to A? Because I think the database mapping to model is wrong in that case. You've already established the FK relationship from the PK of B to either A.foo_id or A.bar_id.
Also be careful with your cascading rules on a relationship like this. SQL Server will reject two FKs to the same table unless the DB action for cascading is "no action".
I do happen to know that what you're trying to do is possible in JPA, since I just recently did it on an entity myself:
#OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
#Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
#JoinColumn(name = "portal_logo_id", referencedColumnName = "id", nullable = true)
private PortalResourceModel logo;
#OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
#Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
#JoinColumn(name = "portal_favicon_id", referencedColumnName = "id", nullable = true)
private PortalResourceModel favicon;
I also don't have a mapping in PortalResourceModel for logo or favicon, because that side of the relationship doesn't know how it is being used. And I can't have a generic mapping from multiple relationships on the owning side to a single relationship on the mappedBy side.
I have 2 classes with OneToMany one-directional relationship.
class A {
#Column(name = "a_id")
Integer id;
#OneToMany
#JoinColumn(name = "a_id")
private List<B> listOfB;
//getters and setters
}
class B {
Integer id;
String name;
#Column("a_id")
Integer aId;
//getters and setters
}
In database I already have saved instance of B.
I need to do:
a.listOfB.add(b);
save(a);
In object b in database I have id and name, but fk is null. I need to update fk, but before it I need to fetch object b;
How can I do it?
Only by writing custom method, or Hibernate/JPA have its own method to fetch objects?
Your mapping is not very common. Common way to have #JoinColumn in B and mappedBy = "a" in A. And you can specify cascade. In the simplest case cascade = CascadeType.ALL.
class A {
#Column(name = "a_id")
Integer id;
#OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
private List<B> listOfB = new ArrayList<B>;
public void addB(B b) {
b.setA(this);
listOfB.add(b);
}
}
class B {
Integer id;
String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id")
private A a;
}
To solve your issue
save(a);
b.setA(a);
saveOrUpdate(b);
And cascade will help you to do the same by almost your way with a help of addB() method
a.addB(b);
save(a);
I am using Hibernate 4.1.10.Final as my JPA provider, Spring and Spring MVC. There are two entities:
#Entity
#Table(name = "a")
public class A {
#Id
private String id;
#OneToMany(mappedBy = "a", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<B> bs;
}
#Entity
#Table(name = "b")
public class B {
#Id
private String id;
#ManyToOne
#JoinColumn(name = "fk_a_id")
private A a;
}
I need to get an A and it's bs, so I use the find(A.class,id) of EntityManager.
A a1 = em.find(A.class, id);
a1.getBs().size();
For which the result is: the size of bs is zero (which means that there is no associated B).
But I'm sure that there are many associated Bs in the database, and indeed the data can been loaded from database while checking via the console.
When I use Query:
Query query = em.createQuery("SELECT a FROM A AS a WHERE a.id = ?1",A.class);
query.setParameter(1, id);
A a= (A) query.getSingleResult();
a.getBs().size(); // = 22
I instead get a size = 22.
What's wrong?
Since you used the mappedBy property in your #OneToMany, the owner of the relation is B and not A. That's why when you load an instance of A, the corresponding Bs are not loaded. Try modifying your annotations with the following :
In class A :
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name="fk_a_id")
private Set<B> bs;
In class B :
#ManyToOne
#JoinColumn(name = "fk_a_id", insertable=false, updatable=false)
private A a;
I am using:
Spring 3.2
Hibernate 4.1.9
I need to map, with JPA, three classes. Class A has a ManyToMany relationship with Class B. A unique combination of Class A and Class B need to own a collection of Class C.
Table A
foo
id | name
Table B
bar
id | name
Table C
data
id | xrefId
Join Table -- Unique Key on (fooId,barId)
xref
id | fooId | barId
Altering the existing data structure is not an option.
Edit 1:
Goal: Load a Foo, get its collection of Bars. From each Bar, get its (their!) collection of Data.
Class A
#Entity
public class Foo {
#Id
private UUID id;
#ManyToMany(optional = false)
#JoinTable(name = "xref",
joinColumns = { #JoinColumn(name = "fooId") },
inverseJoinColumns = { #JoinColumn(name = "barId") })
private List<Bar> lstBar = new ArrayList<Bar>();
}
Class B
public class Bar {
#Id
private UUID id;
#ManyToMany(mappedBy = "lstBar")
private List<Foo> lstFoo = new ArrayList<Foo>();
}
Class C
public class Data {
#Id
private UUID id;
}
Just KISS. Make another class Xref, which contains id, foo, bar and Set<Data> fields. Make a DAO method to find an Xref using two parameters foo and bar (implement it with a simple HQL). The unique requirement could be achieved by an unique constraint in the database.
It doesn't look good trying to express it just by the class hierarchy, better to use DAOs.
Your join table, xref, has an extra id field, in order to be able to create such a table with JPA you need an extra entity class XRef and then you have to map the relation between A and XRef and betweem B and XRef (both are one-to-many). Then, you can create the entity class C and map the relation between C and XRef. Do you need more help? I don't have time right now to provide the code, but if you need ask and I will try to add it as soon as possible.
Look at this example (used Integer instead of UUID for simplicity, the rest should be OK).
Bar class:
public class Bar {
#Id
private Integer id;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "barId")
private Collection<Xref> xrefCollection;
}
Foo class:
public class Foo {
#Id
private Integer id;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "fooId")
private Collection<Xref> xrefCollection;
}
Xref class:
public class Xref {
#Id
private Integer id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "xrefId")
private Collection<Data> dataCollection;
#JoinColumn(name = "bar_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Bar barId;
#JoinColumn(name = "foo_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Foo fooId;
}
Data Class:
public class Data {
#Id
private Integer id;
#JoinColumn(name = "xref_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Xref xrefId;
}
This code has been automatically generated by NetBeans, provided that all tables and indexes are correctly defined in the DB