Let's say I have the following entities and associations:
Entity A:
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "a", cascade = CascadeType.ALL, orphanRemoval = true)
private List<B> b;
}
Entity B:
#Entity
public class B {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id")
private A a;
#OneToMany(mappedBy = "b", cascade = CascadeType.ALL, orphanRemoval = true)
private List<C> c;
}
Entity C:
#Entity
public class C {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "b_id")
private B b;
}
Using the .findAll() method of the CrudRepository for entity A, it will return each A with its associated B's in a list. Also, each B will have each of its associated C's in a list.
My question is: If I in some cases only want to load all A's with their B's, but I don't want the C's in the B's, would that be possible? Could I create a custom query to do that, or is there another way? I hope it is clear what I want to achieve.
I think your problem is mappedBy values in one side of OneToMany relationships.
mappedBy value must be the the name of variable in the other side. So in your cases, you can do this:
In Entity A: change mappedBy = "citizen" to mappedBy = "a"
In Entity B: change mappedBy = "citizen" to mappedBy = "b"
I know Entity a,b,c is just an example, but you should follow above pattern when designing your models relationships.
Related
I am facing a weird issue where even though all fields are set in the java object, when I save the object hibernate tries to insert null values in the fields.
When I further debugged, I saw that while merging the new entity at this line hibernate generates an empty object and sets to the target instead of setting given entity to the target. This results in insert query with null values.
Am I missing some configuration here? Below are the example entities having associations similar to my case.
class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(nullable = false)
#Enumerated(EnumType.STRING)
#EqualsAndHashCode.Include
private VehicleType vehicleType;
#OneToOne(mappedBy="vehicle", fetch=FetchType.LAZY)
private Car car;
#OneToOne(mappedBy="vehicle", fetch=FetchType.LAZY)
private Truck truck;
}
class Car {
#Id
private Integer id;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#MapsId
#JoinColumn(name = "vehicle_id")
private Vehicle vehicle;
...
}
class Truck {
#Id
private Integer id;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#MapsId
#JoinColumn(name = "vehicle_id")
private Vehicle vehicle;
...
}
I encountered the same problem, in my case I have an application with:
public class Claim extends BaseEntity<Integer> implements Serializable {
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "claimdetailsid", referencedColumnName = "id")
private ClaimDetails claimDetails;
#OneToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "beneficiaryid", referencedColumnName = "id")
private Beneficiary beneficiary;
....
}
When I saved the Claim entity, the Claim and ClaimDetails objects were inserted correctly. The other entities had all the fields null, except the id and the creation date.
I tried changing CascadeType.PERSIST to CascadeType.ALL, that solved my insert problem.
But the delete cascade doesn't work now.
We have a problem with fetching by Id of a subselected entity
Here the structure
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//Other class members;
}
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ValueRestriction("NOTNULL")
#ManyToOne
#JoinColumn(name = "C_ID")
private C c;
#ValueRestriction("NOTNULL")
#JsonIgnore
#ManyToOne
#JoinColumn(name = "A_ID")
private A a;
//Other class members;
}
public class C {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonIgnore
#OneToMany(mappedBy = "c")
#Fetch (FetchMode.SELECT)
private List<B> bs;
#ValueRestriction("NOTNULL")
#JsonIgnore
#ManyToOne
#JoinColumn(name = "A_ID")
private A a;
//Other class members;
}
So when we fetch over hibernate
em().find(B.class, id);
the Hibernate query also fetches the columns of A in the C entity.
This lead in a bigger Entitystructure to an
target lists can have at most 1664 entries
(This is a simple demonstration)
In our case we need the references of Entity A in all of these sub Entities
How can we prevent hibernate to fetch the same object multiple times if it is the ame.
In our cases A will always be the SAME in Entity B and Entity C. The Case that Entity B has a different A Entity than in the C Entity is in our structure not possible.
The problem is that #ManyToOne and #OneToOne by default do eager fetching. Switch to lazy fetching #ManyToOne(fetch = LAZY) to avoid this.
I have multiple back-reference classes in a class. Since I use #JsonBackReference for them, I get an error. I assigned #JsonIdentityInfo annotation for those classes, but I still get the same error.
public class X implements Serializable {
....
//bi-directional many-to-one association to Booking
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "xxA", nullable = false)
#JsonBackReference
private A a;
//bi-directional many-to-one association to Client
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "xxB", nullable = false)
#JsonBackReference
private B b;
...getters setters
}
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "#id")
public class B implements Serializable {
........
//bi-directional many-to-one association to BookedClient
#OneToMany(mappedBy = "b", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonManagedReference
private List < X > xxB;
........ getters setters
}
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "#id")
public class A implements Serializable {
........
//bi-directional many-to-one association to BookedClient
#OneToMany(mappedBy = "a", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonManagedReference
private List < X > xxA;
........ getters setters
}
error:
com.fasterxml.jackson.databind.JsonMappingException: Multiple back-reference properties with name 'defaultReference'
How can I resolve this error? Can I not use multiple back-reference in a class?
According to Jackson's javadoc, both #JsonManagedReference and #JsonBackReference accept a name value that binds them together:
#JsonBackReference("a")
private A a;
#JsonManagedReference("a")
private List < X > xxA;
I also faced this issue, but in the last I resolved it.
//This is parent class
#Entity
#Table(name = "checklist")
#JsonIgnoreProperties("inspection")
public class Checklist implements java.io.Serializable {
#ManyToOne
#JoinColumn(name = "product_id", referencedColumnName = "id")
#JsonBackReference
private Product product;
#OneToMany(mappedBy = "checklists", cascade = CascadeType.ALL)
#JsonManagedReference
private Set<Inspection> inspection = new HashSet<Inspection>();
//Constructor
//Getter and Setter
}
//This is child class
#Entity
#Table(name = "inspections")
public class Inspection {
#ManyToOne
#JoinColumn(name = "chk_id", referencedColumnName = "id")
private Checklist checklists;
//Constructor
//Getter and Setter
}
By mentioning #JsonIgnoreProperties("inspection") and #JsonManagedReference in Parent class
Resolved the issue raised by using two #JSONBackRefrence in same parent class.
So this did actually take me a while...
You can annotate your referencse accordingly using #JsonIdentityReference(alwaysAsId = true) and then leave it off the master reference
#JsonIdentityReference(alwaysAsId = true)
private Set<PackInstructionGroup> groups = new TreeSet<>();
I have the following Schema:
#Entity
public class A{
#OneToMany(mappedBy = "dest",cascade = CascadeType.ALL, orphanRemoval = true)
private Collection<C> myDest; //Owns these
#OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, orphanRemoval = true)
private Collection<C> myParents; //can be reached from these
#ManyToMany
private Collection<B> myOwnB;;
}
#Entity
public class B{
#OneToMany(mappedBy = "forB",cascade = CascadeType.ALL, orphanRemoval = true)
private Collection<C> associatedC;
#ManyToMany(mappedBy = "myOwnB")
private Collection<A> associatedA;
}
#Entity
public class C{
#JoinColumn(referencedColumnName = "myDest")
#ManyToOne
private A dest;
#JoinColumn(referencedColumnName = "myParents")
#ManyToOne
private A owner;
#JoinColumn(referencedColumnName = "associatedC")
#ManyToOne
private B forB;
}
Here, if I delete a record of A or B, all the associated Cs get deleted. Perfect.
So my problem is this:
If I delete a reference of B from A (in that ManyToMany relation), I need all the Cs deleted as well for that A and B. (All Cs where forB=removedB and owner=sourceA). I have now written a similar query and it works fine now that I explicitly execute in my EJB. Is there a workaround or a annotation saying that a record of C gets deleted if one of the attributes(column) become null?
I have the following mapping:
#Entity
public class A{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer aId;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "A_to_B",
joinColumns = {#JoinColumn(name = "aId", referencedColumnName = "aId")},
inverseJoinColumns = {#JoinColumn(name = "bId", referencedColumnName = "bId")})
private Set<B> bList;
and I have the B class:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING)
public abstract class B {
#Id
#Column(name = "bId")
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
}
No referenct of A in B.
I have the following code:
List<A> someAs = .... // Generated
B b = ... // also generated
b.setAList(someAs);
Session session = sessionFactory.openSession();
for (A a : someAs) {
session.save(a);
}
session.save(b);
session.close();
The result is All the A instances are saved. the B instance saved too.
But the join table is not filled so if query for the B instance with left join fetch... I get empty A list.
What can I do?
Since you have defined A as the owning side of the relationship by using #JoinTable, you will have to add the B instances to A in order for them to be saved in the join table:
a.setBList(someBs);
Alternatively, you can change the owning side to B and leave the code as it is.