I have the following scenario:
I have an entity called MyOtherEntity that has a type attribute.
MyEntity is associated only with certain MyOtherEntity entities based on the type of MyOtherEntity.
MyEntity class (only for demonstration it's not modelled correctly):
#Data
#Entity
#Table(name = "my_table")
public class MyEntity {
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "my_entity_my_other_entity_type1",
joinColumns = {#JoinColumn(name = "my_entity_id")},
inverseJoinColumns = {#JoinColumn(name = "my_other_entity_id")}
)
private List<MyOtherEntity> myOtherEntityType1;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "my_entity_my_other_entity_type2",
joinColumns = {#JoinColumn(name = "my_entity_id")},
inverseJoinColumns = {#JoinColumn(name = "my_other_entity_id")}
)
private List<MyOtherEntity> myOtherEntityType2;
// more fields
}
MyOtherEntity class:
#Data
#Entity
#Table(name = "my_other_entity")
public class MyOtherEntity {
private String type;
// more fields
}
A more detailed example:
Let's say there are only 3 types of MyOtherEntity type1, type2, and type3. My goal is to only associate MyEntity with MyOtherEntity entities of type1 and type2.
Is this functionality possible to achieve using Hibernate?
You can use #Where annotation.
#Where(clause = "type = 'tyep1'")
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "my_entity_my_other_entity_type1",
joinColumns = {#JoinColumn(name = "my_entity_id")},
inverseJoinColumns = {#JoinColumn(name = "my_other_entity_id")}
)
private List<MyOtherEntity> myOtherEntityType1;
#Where(clause = "type = 'tyep2'")
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "my_entity_my_other_entity_type2",
joinColumns = {#JoinColumn(name = "my_entity_id")},
inverseJoinColumns = {#JoinColumn(name = "my_other_entity_id")}
)
private List<MyOtherEntity> myOtherEntityType2;
Related
I'm junit testing inside the below function:
#Test
public void testQueryUser(){
User user1 = userRepository.findById(12L).orElse(null);
assertThat(user1)
.hasFieldOrPropertyWithValue("username", "adam");
}
The below is my domain class User:
#Entity
#Table(name = "sys_user")
#Data
#NoArgsConstructor
#AllArgsConstructor
#DynamicUpdate
public class User extends BaseEntity implements Serializable{
#Id
#Column(name = "user_id")
#NotNull(groups = {Update.class})
#Null(groups = {Create.class})
#ApiModelProperty(value = "ID", hidden = true)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(fetch = FetchType.EAGER)
#ApiModelProperty(value = "user_role")
#JoinTable(name = "sys_users_roles",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "role_id", referencedColumnName = "role_id")})
private Set<Role> roles;
#ManyToOne
#JoinColumn(referencedColumnName = "dept_id")
private Dept dept;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "sys_user_jobs",
joinColumns = {#JoinColumn(name="user_id", referencedColumnName = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "job_id", referencedColumnName = "job_id")})
private Set<Job> jobs;
#NotBlank
#Column(unique = true)
#ApiModelProperty(value = "username")
private String username;
}
Got the below error message as expected:
java.lang.AssertionError:
Expecting
User(id=12, roles=[], dept=null, jobs=[], username=adam)
to have a property or a field named "username" with value
"adam"
but value was:
"paul"
But when switching #ManyToMany(fetch = FetchType.EAGER) back to #ManyToMany(fetch = FetchType.LAZY) inside domain class
I got
org.hibernate.LazyInitializationException: failed to lazily initialize
a collection of role: com.adminsys.modules.system.domain.User.roles,
could not initialize proxy - no Session
My questions are:
I'm only testing the field username but why JUnit is looking into field roles?
Why no session?
What's the best practice for my scenario?
There is an entity call Version and this entity has an inner join many-to-many relationship. The bridge table VER_EQUIVALENTS has columns [VER_ID, EQUIVALENT_VER_ID, CODE] and the CODE column contains the code of the equivalent version.
This is how I implemented this relationship.
public class Version {
private String code;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "VER_EQUIVALENTS",
joinColumns = {#JoinColumn(name = "VER_ID")},
inverseJoinColumns = {#JoinColumn(name = "EQUIVALENT_VER_ID")}
)
#MapKey(name = "code")
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
private Map<String, Version> equivalentVersions = new HashMap<String, Version>();
}
This is what I got when I try to insert a version contains equivalent versions.
ORA-01400: cannot insert NULL into ("VER_EQUIVALENTS"."CODE")
What can I do to set the CODE value?
If I correctly understand that you need, you should correct your mapping in the following way:
public class Version {
// ...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "VER_EQUIVALENTS",
joinColumns = {#JoinColumn(name = "VER_ID")},
inverseJoinColumns = {#JoinColumn(name = "EQUIVALENT_VER_ID")}
)
#MapKeyColumn(name = "CODE")
private Map<String, Version> equivalentVersions = new HashMap<String, Version>();
}
I have a problem with the definition of the OneToOne bidirectional relationship with the same entity.
In particular, I defined a class User and I wanted to give it an attribute partner, that is a User itself.
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true)
private Long ID;
...
#OneToOne(cascade = CascadeType.ALL, targetEntity = User.class)
#JoinTable(
name = "user_partners",
joinColumns = {#JoinColumn(name = "u1", referencedColumnName = "ID")},
inverseJoinColumns = {#JoinColumn(name = "u2", referencedColumnName = "ID")}
)
private User partner;
...
}
Now, if I test this case defined in my repository UserRepository.java:
...
User um = new User(...);
User uf = new User(...);
um.setPartner(uf);
...
I would expect that both um and uf have the reference to their partner. Instead, only um has the reference as I explicitly defined it.
What am I doing wrong?
I have a productJob table and a quadrat table. Every quadrat can be installed on many productJob and every productJob can have between 1 and 4 quadrats of the same or different kinds! I'm interested to keep the order of quadrat installation on the product jobs. For example first, second, third or forth place! But the following mapping doesn't create the order column on the JoinTable telai_quadrati. What is the problem of my mapping? The orderColumn isn't created in anyway!
#Entity
#Table(name = "telai")
public class ProductJob implements IProductJob, IProductJobProcessing{
#Embedded private QuadratGroup quadrateGroup = new QuadratGroup();
}
#Embeddable
public class QuadratGroup implements Serializable{
#OneToMany(targetEntity = Quadrat.class, cascade = CascadeType.ALL)
#JoinTable(
name = "telai_quadrati",
joinColumns = {#JoinColumn(name = "dbId", table = "telai")},
inverseJoinColumns = {#JoinColumn(name = "id", table = "quadrati")})
//#OrderColumn(name = "order")
#IndexColumn(name = "order")
public List<Quadrat> getQuadratList(){ //return an ordered list of the quadrats with at most 4 elements}
And it is clear that for the quadrats there exists no order so I use set!
#Entity
#Table(name = "quadrati")
public class Quadrat implements IQuadrat, Cloneable, Serializable{
#ManyToMany
#JoinTable(
name = "telai_quadrati",
joinColumns = #JoinColumn(name = "id", table = "quadrati"),
inverseJoinColumns = #JoinColumn(name = "dbId", table = "telai"))
private Set<ProductJob> productJobs;
It works if I use property access inspite of method access! Like this:
#OneToMany(targetEntity = Quadrat.class, cascade = CascadeType.ALL)
//#MapKeyJoinColumn(name="indice" , table = "telai_quadrati")
#JoinTable(
name = "telai_quadrati",
joinColumns = {#JoinColumn(name = "telaio_id", table = "telai")},
inverseJoinColumns = {#JoinColumn(name = "quadrato_id", table = "quadrati")})
#OrderColumn(name = "indice")
private List<Quadrat> quadratList;
But I wonder why it doesn't work with method access that forces me a heavy refactor in my project! :(
I have ManyToMany mapping like this:
#XmlTransient
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name = "users_clients",
joinColumns = {#JoinColumn(name = "user_id")},
inverseJoinColumns = #JoinColumn(name = "client_id"))
public List<Client> getClients() {
return clients;
}
And other side:
#ManyToMany(mappedBy = "clients")
private List<User> users = new ArrayList<User>();
So as you can see I have JoinColumn name = user_id and client_id but hibernate mapps this columns with names userS_id and clientS_id as their tables names. Why that happening? Any suggestions?
Try specifying the column name in your #JoinColumn annotation. Also you were missing braces around the inverseJoinColumns
#JoinTable(name = "users_clients",
joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName="user_id")},
inverseJoinColumns = {
#JoinColumn(name = "client_id", referencedColumnName="client_id")})