Java Hibernate map list of list of entities #AssociationOverrides - java

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 ?

Related

Proper mapping ( JPA ) composite key

For example i have
entities
#Entity
public class A{
#Id
Long Id;
...
}
#Entity
public class B{
#Id
Long Id;
...
}
#Entity
#IdClass(ABId.class).
public class AB{
#Id
#ManyToOne
private A a;
#Id
#ManyToOne
private B b;
private boolean state;
}
Class for composite primary key:
public ABId implements Serializable{
Long a;
Long b;
.........
}
and i want to get from class A something like this select * from AB ab where ab.a_id=1; ( id from A object)
i did such mapping in class A
#OneToMany(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="A_id", referencedColumnName="id"),
#JoinColumn(name="B_id", referencedColumnName="id")
})
List<AB> listAB;
but it does nothing i alawys get empty list.
Solved,
I did mapping
#OneToMany(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="A_id", referencedColumnName="id")
})
List<AB> listAB;
and it works like it should.

How to save two related objects to data base with relation OneToOne

When I'm trying to save an U object I got next exception:
org.springframework.orm.jpa.JpaSystemException: attempted to assign id from null one-to-one property [com.roc.domain.A.user]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [com.roc.domain.A.user]
I have two tables:
1. user that columns are id(auto incr, primary), name.
2. contact that columns are id, user_id(that is foreign key -> user.id) and address.
#Entity
#Table(name = "a")
public class A {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name="address")
private String address;
#OneToOne
#MapsId
private U user;
public A() {
}
// getters and setters
}
#Entity
#Table(name = "u")
public class U {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name="username")
private String userName;
#JoinColumn(name = "user_id", referencedColumnName = "id")
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private A a;
public U(){};
}
#RunWith(SpringRunner.class)
#SpringBootTest
public class ApplicationTest {
#Autowired
private URepository uRepository;
#Test
public void simpleCrudTest() {
U user = new U("name", new A("address"));
uRepository.save(user);
}
}
You have set the cascade correctly however because the relationship is bi-directional you need to set both sides in the in-memory model.
#Test
public void simpleCrudTest() {
U user = new U("name", new A("address"));
//will work when this is added
a.setUser(user);
uRepository.save(user);
}
Otherwise, as the error states, A has a null reference for user on save.
Edit: To save using a single repository save call.
#Entity
#Table(name = "a")
public class A {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "address")
private String address;
#OneToOne
#MapsId
private U user;
public A() {
}
}
#Entity
#Table(name = "u")
public class U {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "username")
private String userName;
#JoinColumn(name = "user_id", referencedColumnName = "id")
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private A a;
public U() {
};
// method to manage the bidirectional association
public U addToA(A a) {
this.a.add(a);
a.setUser(this);
}
}
#RunWith(SpringRunner.class)
#SpringBootTest
public class ApplicationTest {
#Autowired
private URepository uRepository;
#Test
public void simpleCrudTest() {
U user = new U();
user.addToA(new A("address"));
user.setUserName("username");
uRepository.save(user);
}
}
Also, you refer to this link.
inserting values into multiple tables using hibernate
You have to save A first, Then set saved A to U and save U.
#RunWith(SpringRunner.class)
#SpringBootTest
public class ApplicationTest {
#Autowired
private URepository uRepository;
#Autowired
private ARepository aRepository;
#Test
#Trascational
public void simpleCrudTest() {
A a = new A();
a.setAddress("address");
a = aRepository.save(a);
U user = new U("name", a);
uRepository.save(user);
}
}

Hibernate not finding map property

So I am getting the exception:
org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: se.mulander.cosmos.movies.model.Cast.starredIn in se.mulander.cosmos.movies.model.ExtendedMovie.cast
But I can't really figure out why.
The two objects that I am going to map are:
#Entity
#Table(name = "cast")
#ApiModel(description = "A cast member that has been part of making the movie")
public class Cast
{
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
#JoinColumn(name = "movie_id")
public ExtendedMovie starredIn;
}
and
#Entity
#Table(name = "extended_movie")
public class ExtendedMovie
{
#OneToMany(cascade = {CascadeType.ALL}, mappedBy = "starredIn", orphanRemoval = true)
#LazyCollection(LazyCollectionOption.FALSE)
public List<Cast> cast = new ArrayList<>();
}
I have stripped them of some other properties, but in essence this is the relationship that is not working.
So what I don't get is why it says that it is an unknown property, as the property is public and hibernate shouldn't have any problems mapping it.
what is it that I am missing here?
Try something like:
ExtendedMovie :
#Entity
public class ExtendedMovie implements Serializable {
private static final long serialVersionUID = 6771189878622264738L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#JoinColumn(name = "cast_id", referencedColumnName = "id")
private Set<Cast> cast;
public Set<Cast> getCast() {
return cast;
}
public void setCast(Set<Cast> cast) {
this.cast= cast;
}
}
Cast:
#Entity
#ApiModel(description = "A cast member that has been part of making the movie")
public class Cast implements Serializable {
private static final long serialVersionUID = 6771189878622265738L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
//Remove extendedmovie from here
//other property getter and setters here
}
This will establish a one-to-many relationship between ExtendedMovie and Cast.

JAXB Unmarshalling Entities - References null

I have 2 mapping classes (analogue to JPA classes):
AElement.java
#XmlType(propOrder = {"name", "children", })
#XmlRootElement(name = "a")
#XmlAccessorType( XmlAccessType.PROPERTY)
public class AElement implements Serializable {
private String name;
private List<BElement> children;
#XmlElement(name = "metadatum")
public List<BElement> getChildren(){
return children;
}
...
}
BElement.java
#XmlRootElement(name = "b")
#XmlType(propOrder = {"name"})
public class BElement implements Serializable{
private String name;
private AElement parent;
...
}
A and B are in a OneToMany relation. The XML should look like this:
<A>
<B></B>
<B></B>
</A>
If I unmarshal the xml, map it to my JPA classes and persist it to my database everything is
stored correctly except my references. This means that B is stored without a foreign key to A in the database.
I'm using JPA with Hibernate. Following my JPA classes:
A.java
#Entity
public class A implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
private String name;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "parent")
private List<B> children;
public List<B> getChildren(){
return children;
}
...
}
B.java
#Entity
public class B implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
private String name;
#ManyToOne(optional = true)
#JoinColumn(name = "a_id", referencedColumnName = "id")
private A parent;
...
}
Looks like I have to assign the appropriate A to each B. This solves my problem.
a.getB().forEach(b -> b.setA(a));
I don't know If it is a good workaround? Especially because I have other entities that are children of B.
Found a solution:
Method afterUnmarshal in class BElement.java
public void afterUnmarshal(Unmarshaller u, Object parent) {
this.a = (AElement)parent;
}

Hibernate create alias on many to many list

I have four class; UserGroup, UserAccount, Role, UserGroupRoleRelation and my db is IBM DB2
#Entity
#Table(name = "USER_GROUP")
public class UserGroup implements Serializable {
#Id
#Column(name = "USER_GROUP_ID")
#GeneratedValue
private Long id;
......
..
#OneToMany(mappedBy = "userGroup", cascade = CascadeType.ALL, orphanRemoval = true)
private List<UserGroupRoleRelation> userAccountsRole = new ArrayList<UserGroupRoleRelation>();
}
#Entity
#Table(name = "ROLE")
public class Role implements Serializable {
#Id
#Column(name = "ROLE_ID")
#GeneratedValue
private Long id;
......
#OneToMany(mappedBy = "role")
private List<UserGroupRoleRelation> userAccountInGroup = new ArrayList<UserGroupRoleRelation>();
}
#Entity
#Table(name = "USER_GROUP_ROLE_LINE", uniqueConstraints = #UniqueConstraint(columnNames = { "ROLE_ID", "USER_GROUP_ID" }))
public class UserGroupRoleRelation {
#Id
#GeneratedValue
#Column(name = "RELATION_ID")
private Long relationId;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "USER_ACCOUNT_USER_GROUP_ROLE_LINE", joinColumns = { #JoinColumn(name = "RELATION_ID") }, inverseJoinColumns = { #JoinColumn(name = "USER_ID") }, uniqueConstraints = #UniqueConstraint(columnNames = { "USER_ID", "RELATION_ID" }))
private List<UserAccount> userAccountList = new ArrayList<UserAccount>();
#ManyToOne
#JoinColumn(name = "USER_GROUP_ID")
private UserGroup userGroup;
#ManyToOne
#JoinColumn(name = "ROLE_ID")
private Role role;
}
#Entity
#Table(name = "USER_ACCOUNT")
public class UserAccount implements Serializable {
#Id
#Column(name = "USER_ID")
#GeneratedValue
private Long id;
.....
#ManyToMany(mappedBy = "userAccountList", cascade = CascadeType.ALL)
private List<UserGroupRoleRelation> rolesInGroup = new ArrayList<UserGroupRoleRelation>();
}
I wanna find usergroups of a useraccount and i prepared a method with criteria. its like;
#Override
#Transactional
public List<UserGroup> findUserGroupOf(UserAccount userAccount) {
Criteria criteria = getSession().createCriteria(UserGroup.class);
criteria.createAlias("userAccountsRole", "userAccountsRole");
criteria.add(Restrictions.eq("userAccountsRole.userAccountList", userAccount));
return criteria.list();
}
But when i try to get result of that method, DB2 gives to me DB2 SQL Error: SQLCODE=-313, SQLSTATE=07004, SQLERRMC=null, DRIVER=3.63.75
Probably its about creating alias on many to many relation. I dont know what should i do to create alias on many to many. How can I get result of that function?
Thank
#Override
#Transactional
public List<UserGroup> findUserGroupOf(UserAccount userAccount) {
Criteria criteria = getSession().createCriteria(UserGroup.class);
criteria.createAlias("userAccountsRole", "userAccountsRole");
criteria.createAlias("userAccountsRole.userAccountList", "userAccountList");
criteria.add(Restrictions.eq("userAccountList.id", userAccount.getId()));
return criteria.list();
}
It works for me. I mean criteria on "id". But I don't understand why I cant check equality on object instead of id when there is ManyToMany list
It is not of creating alias. You are passing an object to hibernate on which it can not make any criteria. You need to create bidirectional mapping for that.Or else if you your requirement is just to fetch the the list of UserAccountList of particular UserGroup class you can follow the below code.
#Override
#Transactional
public List<UserGroup> findUserGroupOf(long userGroupId) {
Criteria criteria = getSession().createCriteria(UserGroup.class);
criteria.add(Restrictions.eq("id",userGroupId));
criteria.createAlias("userAccountsRole", "uar");
criteria.setFetchMode("uar.userAccountList",FetchMode.JOIN);
return criteria.list();
}

Categories