I have Order and Dish Entities. Order contains a map of Dish-Integer ( dish and how many times it was ordered ).
But I can't figure out what to write above map when I have a key as an Entity. How join column should look like.
#Entity
public class Order {
#OneToMany(
mappedBy = "order",
cascade = CascadeType.ALL,
orphanRemoval = true)
private Map<Dish, Integer> dishesQuantity = new HashMap<>();
}
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public class Dish {
private Order order;
}
P.S. I would also appreciate it if you could tell me what happens if I skip annotating the join column.
try this
public class Order {
#OneToMany(
mappedBy = "order",
cascade = CascadeType.ALL,
orphanRemoval = true)
private Map<Dish, Integer> dishesQuantity = new HashMap<>();
}
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name ="dishes_quantity")
public class Dish {
private Order order;
}
As I know to use #JoinColumnis mapping foreign key. To use #JoinColumn annotation you can set foriegnkey name. If you don't use it. It will be automapping with Entity_ID of opposite entity field.
But I usually set #JoinColumn(name ='') to mapping field clearly.
Related
I have a scenario like below.
Lets say EntityA has three nested entities EntityB, EntityC, EntityD. And all of EntityB, EntityC, EntityD has several nested entities inside them.
But while selecting for EntityA it selects the whole tree of nested entities. Whereas I want to fetch a specific branch. Lets say only EntityA, EntityB and all sub entities of EntityB are to be fetched leaving EntityC and EntityD back then I am not sure how to do that. As spring jpa brings all the nested objects back to me.
I am using below collection mapping.
#Entity
#Table(name = "customer_party_mapping")
#Data
public class CustomerPartyMappingEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "customer_id")
private Integer custmerId;
#Column(name = "orgtype_id")
private Integer orgTypeId;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "customer_party_mapping_id")
#Fetch(value = FetchMode.SUBSELECT)
private List<CustomerPartyBookingLocationEntity> customerPartyBookingLocation=new ArrayList<CustomerPartyBookingLocationEntity>();
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "customer_party_mapping_id")
#Fetch(value = FetchMode.SUBSELECT)
private List<CustomerPartyFieldMappingEntity> customerPartyFieldMappingEntity=new ArrayList<CustomerPartyFieldMappingEntity>();
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "customer_party_mapping_id",referencedColumnName="id")
#Fetch(value = FetchMode.SUBSELECT)
private List<CustomerPartyOtherDocumentEntity> otherDocumentsList=new
ArrayList<>();
#OneToOne( cascade={ CascadeType.PERSIST, CascadeType.MERGE })
#JoinColumn(name = "customer_name_screening_id", referencedColumnName="id")
private CustomerNameScreeningEntity customerNameScreeningEntity;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "customer_party_mapping_id")
#Fetch(value = FetchMode.SUBSELECT)
private List<CustomerDocInfoTrackingEntity> customerDocInfoTrackingList=new
ArrayList<CustomerDocInfoTrackingEntity>();
}
And I am calling
List<CustomerPartyMappingEntity> customerPartyMappingEntityList = customerPartyMappingRepository.findByCustmerId(customerid);
It gets all the nested mapped list of entities wheras I need only CustomerPartyMappingEntity and its list of customerPartyFieldMappingEntity nested object.
Any help will be appreciated.
First use FetchType.LAZY for nested entity.
Then you can use #EntityGraph to fetch nested entity by name and their nested entity using their name with . in the repository. You use to just specify the nested property in attributePaths like
#EntityGraph(attributePaths = {"customerPartyBookingLocation"})
And the nested property of customerPartyBookingLocation like
#EntityGraph(attributePaths = {"customerPartyFieldMappingEntity.subField"})
Example:
#EntityGraph(attributePaths = {"customerPartyBookingLocation", "customerPartyFieldMappingEntity.subField"})
List<CustomerPartyMappingEntity> findByCustmerId(Integer customerid);
Note: You can't use #EntityGraph with #Query annotation
If your entities are really setup correctly, see for instance the subselect example here and remove your EAGER (you are currently instructing hibernate to fetch all these fields upon entity initialization). It should work.
I have 2 Entities:
public class Restaurant {
#OneToMany(fetch = FetchType.LAZY, mappedBy = "restaurant")
private Set<Vote> votes;
}
and
public class Vote {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "restaurant_id", nullable = false)
private Restaurant restaurant;
}
if I try to get both of them like that
#Query("SELECT r FROM Restaurant r JOIN FETCH r.vote ")
I get Infinite Recursion with Jackson JSON. So I managed to find a way to handle that:
public class Restaurant {
#JsonManagedReference
#OneToMany(fetch = FetchType.LAZY, mappedBy = "restaurant")
private Set<Vote> votes;
}
public class Vote {
#JsonBackReference
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "restaurant_id", nullable = false)
private Restaurant restaurant;
}
Now I can get restaurant with votes like that?
#Query("SELECT r FROM Restaurant r JOIN FETCH r.vote ")
But now I CAN'T GET Votes with restaurant
#Query("SELECT v FROM Vote v JOIN FETCH v.restaurant ")
because #JsonBackReference meant
private Restaurant restaurant;
wont be serialized. But i need both of this bidirectional relationship in my controllers. What should i do?
For serialization of entities with bidirectional relationship use #JsonIdentityInfo and remove the #JsonBackReference and #JsonManagedReference. The property of the #JsonIdentityInfo refer to your entity id property used to identify entity.
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Restaurant {
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Vote {
I have a set entities such as:
public class EntityToDrop {
#NaturalId
#ManyToOne(fetch = FetchType.EAGER)
private ParentEntity parentEntity;
#OneToMany(mappedBy = "entityToDrop", cascade = {CascadeType.REMOVE, CascadeType.REFRESH}, orphanRemoval = true)
private Set<OtherEntity> otherEntities= new HashSet<>();
[...] (other fields and relationships)
}
public class ParentEntity {
#OneToMany(mappedBy = "parentEntity", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<EntityToDrop> childEntities = new HashSet<>();
[...]
}
public class OtherEntity{
#ManyToOne(optional = true,fetch = FetchType.EAGER)
#NaturalId
private EntityToDrop entityToDrop;
[...]
}
In some part of the code I'm calling
parentEntityInstance.getChildEntities().remove(entityToDrop);
[...]
entityManager.persist(parentEntityInstance);
Which I expect should always remove entityToDrop from the database, since it's marked with orphanRemoval. However, when the relationship with OtherEntity exists it's not getting removed, and more interestingly, if I remove the relationship with OtherEntity then try to remove it from the ParentEntity in the same transaction, it's not getting dropped either.
Is there any case where orphanRemoval = true will not work as I expect it to? And as a followup how would I figure out what's stopping my entity from being removed in this case?
I made some domains below.
#Entity
public class Conference {
...
#OneToMany(
targetEntity = ProgramDate.class,
mappedBy = "conference",
cascade = CascadeType.REMOVE,
fetch = FetchType.EAGER
)
#JsonBackReference
private List<ProgramDate> programDateList;
}
#Entity
public class Program {
...
#ManyToOne
#JoinColumn(name = "program_date_id")
#JsonBackReference
private ProgramDate date;
#ManyToOne
#JoinColumn(name = "room_id")
private Room room;
...
}
#Entity
public class ProgramDate {
...
#OneToMany(
targetEntity = Program.class,
mappedBy = "date",
fetch = FetchType.EAGER
)
#JsonBackReference
private List<Program> programList;
#ManyToOne
#JoinColumn(name = "conference_id")
private Conference conference;
}
#Entity
public class Room {
...
#OneToMany(
targetEntity = Program.class,
mappedBy = "room",
fetch = FetchType.EAGER
)
#JsonBackReference
private List<Program> programList;
}
And I made freemarker like below code.
<#list conference.programDateList as date>
...
</#list>
I meet a problem that is infinite recursion reference with JPA OneToMany, ManyToOne Relationship. I try to add #JsonBackReference, but it only resolved about the json recursive problem.
Use json ignore annotation :
#OneToMany(
targetEntity = Program.class,
mappedBy = "date",
fetch = FetchType.EAGER
)
#JsonIgnore
private List<Program> programList;
Why do you include Room & Programdate in Conference, then in Program add a Conference along a Room & a Programdate which should already be contained in Conference ? Then in ProgramDate you have another reference to... conference and a list of program...
Basically you shouldn't try to "hack" out of these loops with some fancy annotations, but you should work on your data model. While Conference looks ok, Program could be a list of conferences only, and a Programdate should be... a date.
I have Persistent class, referring to many collections with LAZY fetch type, like
#Entity
#Table(name = "TABLE")
public class Table implements Serializable {
....
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "LIST1", nullable = true)
private ArrayList list1;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "LIST2", nullable = true)
private ArrayList list2;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "LIST1", nullable = true)
private ArrayList list1;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "LIST2", nullable = true)
private ArrayList list2;
....
}
I have instantiated some objects of type TABLE through Hibernate, added it to a list of Tables, and now want to fetch one of this collections (say list2) for all objects in this list.
for(Table table:tables){
result=table.list2;
....
}
But this way Hibernate will generate sequence of separate SQL queries. Can hibernate fetch list2 for all the objects in collection in one query? (It is important not to create new Table class instances, but modify objects, that are already exists)
From the reference manual:
A "fetch" join allows associations or collections of values to be
initialized along with their parent objects using a single select.
This is particularly useful in the case of a collection. It
effectively overrides the outer join and lazy declarations of the
mapping file for associations and collections.
select t from Table t
left join fetch t.list2
where ...
You should map list2 property with generics. Lets say:
#Entity
#Table(name = "TABLE")
public class Table implements Serializable {
....
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "LIST1", nullable = true)
private List<OtherClass> list1;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "LIST2", nullable = true)
private List<OtherClass> list2;
}
HQL query for that:
select list2 from Table
So lets say you are using hibernate template to fetch data:
List<OtherClass> result = getHibernateTemplate().find("select list2 from Table");