MySql: Relation between Diseases and Symptoms - java

I'm working on a Spring Boot App project, which works with diseases and symptoms. So i'm thinking, if a disease can have more symptoms, and also, a symptom can be linked to more diseases, that means i'll have a many-to-many relation in MySql. Also, a symptom can be a general symptom for one disease, and a specific symptom for another (each disease has it's general and specific symptoms). Does this mean i have to have TWO many-to-many relations between diseases and symptoms?
And i'm not certain i really need for each symptom to have a list of diseases where it is a general symptom, and a list where it is a specific one.
I'm pretty new to MySql, so i was wondering if this is the most optimal solution. Any input would be appreciated:
#Entity
public class Disease implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private DiseaseGroup group;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "disease_generalSymptoms",
joinColumns = { #JoinColumn(name = "disease_id") },
inverseJoinColumns = { #JoinColumn(name = "symptom_id") })
private ArrayList<Symptom> generalSymptoms = new ArrayList<Symptom>();
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "disease_specificSymptoms",
joinColumns = { #JoinColumn(name = "disease_id") },
inverseJoinColumns = { #JoinColumn(name = "symptom_id") })
private ArrayList<Symptom> specificSymptoms = new ArrayList<Simptom>();
}
#Entity
public class Symptom implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false)
private String name;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "symptom")
private ArrayList<Disease> diseasesWhereThisIsAGeneralSymptom = new ArrayList<Disease>();
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "symptom")
private ArrayList<Disease> diseasesWhereThisIsASpecificSymptom = new ArrayList<Disease>();
}

Related

How to implement many to many relationship in spring boot mongo db

I have two Entities in my Spring-Boot mongoDb Application:
Course.java
#Entity
#Table(name = "students")
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
String title;
#Enumerated(EnumType.STRING)
OptionCourse optionCourse;
private double fee;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "courses")
private Set<Student> student = new HashSet<>();
}
and
Student.java
Entity
#Table(name = "students")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
int age;
String department;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "student_courses",
joinColumns = { #JoinColumn(name = "student_id") },
inverseJoinColumns = { #JoinColumn(name = "course_id") })
private Set<Course> courses = new HashSet<>();
}
for my mongoDb database:
I want to realise a Many-to-Many-Relationship between both Entities. Every courses should be able to assign multiple student.
How can i replace my annotations (#Entity, #Table,#Id, #Enumerated(EnumType.STRING) and #ManyToMany(fetch = FetchType.LAZY,...)) in my entities. I use spring-boot-starter-data-mongodb in my maven dependencies

Mutiple #ManyToMany on a single Entity causes Cross Join

I have a User Entity.
#Entity
#Table(name = "t_login_user")
public class User extends Auditable<Long> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long id;
#Column(name = "user_uid")
private String userUid;
#Column(name = "user_name")
private String userName;
#OneToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name="primary_role_id")
private Role primaryRole;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "t_login_user_role_map", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
private List<Role> roles;
}
My Role Entity is
#Entity
#Table(name = "t_login_role")
public class Role extends Auditable<Long> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="role_id")
private Long roleId;
#Column(name="role_code")
private String roleCode;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "t_login_role_priv_map", joinColumns = #JoinColumn(name = "role_id"), inverseJoinColumns = #JoinColumn(name = "priv_id"))
private List<Privilege> privileges;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "t_login_role_menu_map", joinColumns = #JoinColumn(name = "role_id"), inverseJoinColumns = #JoinColumn(name = "menu_id"))
private List<Menu> menus;
}
My Menu Entity is
#Entity
#Table(name = "t_login_menu")
public class Menu extends Auditable<Long> implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private Long id;
#Column(name="menu_text")
private String menuText;
#Column(name="menu_icon")
private String menuIcon;
#Column(name="menu_url")
private String menuURL;
}
As you can see my Role has multiple Privileges and Multiple Menus. The problem I face is that when I have a code like
LoggedinUser liu = (LoggedinUser)authentication.getPrincipal();
List<Menu> menus = liu.getPrimaryRole().getMenus();
If I have two privileges say READ_DATA and WRITE_DATA
And three Menus 1. HOME 2.USER 3.PROFILE
my menus variable has a value of [HOME,HOME,USER, USER, PROFILE, PROFILE] (i.e. 2 privileges * 3 Roles)
I suspect that this is due to my Role entity having more than one #ManyToMany annotations.
I tried to search online and Stackoverflow but no results.
Anybody face this issue? Am i doing something fundamentally wrong?
Okay. I understand where the cross join happens. Since both the ManyToMany are being EAGER loaded, this is where the Cross Join Happens.
If I change to LAZY Load then the issue disappears. Slight performance hit on LAZY load, but thats fine since I do it only once and store the result in the session.

Nested n:m + attributes JPA

I have a strange need in a project. Joining two n:m+attributes table (I will present the behavior with dummy attributes).
FirstTable (idPlace, idAddress,idSchool, wage) joined 1:m;
SecondTable (idPlace, idAddress,idSchool, qty, idEnterprise)
EDIT (example schema):
Of course that I have the tables Place, Address, School, Enterprise with theirs respective Ids, gets, sets and attributes implemented in the entity classes.
CODE:
Place
#Entity
#Table(name = "Place")
public class Place implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idLine")
private Long idLine;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pk.place")
private List<FirstTable> firstTables;
}
Address
#Entity
#Table(name = "Address")
public class Address implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idAddress")
private Long idAddress;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pk.address")
private List<FirstTable> firstTables;
}
School
#Entity
#Table(name = "School")
public class School implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idSchool")
private Long idSchool;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pk.school")
private List<FirstTable> firstTables;
}
FirstTable
#Entity
#Table(name = "FirstTable")
#AssociationOverrides({ #AssociationOverride(name = "pk.school", joinColumns = #JoinColumn(name = "idSchool")),
#AssociationOverride(name = "pk.address", joinColumns = #JoinColumn(name = "idAddress")),
#AssociationOverride(name = "pk.place", joinColumns = #JoinColumn(name = "idPlace")) })
public class FirstTable implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#EmbeddedId
protected FirstTablePK pk = new FirstTablePK();
}
FirstTablePK
#Embeddable
public class FirstTablePK implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#ManyToOne
private Address address;
#ManyToOne
private Place place;
#ManyToOne
private School school;
}
The above mentioned tables and joins are working perfectly. Now I want to join the FirstTable with the Second Table.
Enterprise
#Entity
#Table(name = "Enterprise")
public class Enterprise implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idEnterprise")
private Long idEnterprise;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pk.enterprise")
private List secondTables;
}
Now for the SecondTable I've followed the same logic to connect to the Enterprise. For connecting with the FirstTable I've tried this:
#Entity
#Table(name = "SecondTable")
#AssociationOverrides({
#AssociationOverride(name = "pk.firstTable", joinTable = #JoinTable(
name = "FirstTable", inverseJoinColumns = {
#JoinColumn(name = "idSchool", referencedColumnName = "idSchool"),
#JoinColumn(name = "idAddress", referencedColumnName = "idAddress"),
#JoinColumn(name = "idPlace", referencedColumnName = "idPlace") })),
#AssociationOverride(name = "pk.enterprise", joinColumns = #JoinColumn(name = "idEnterprise")) })
public class SecondTable implements Serializable{}
Something is not working in my annotation, I'm trying to do an inverseJoin to the FirstTable table. The compilation shows this error:
"org.hibernate.AnnotationException: A component cannot hold properties split into 2 different tables"
I've tried to provide a MV example.
Thanks in advance and I really need your help.
Hours later and many tries before I've managed to solve the problem. Actually the solution was much simpler that I was thinking initially.
Here it is:
#AssociationOverride(name = "pk.firstTable", joinColumns = {
#JoinColumn(name = "idSchool"),
#JoinColumn(name = "idAddress"),
#JoinColumn(name = "idPlace") }),
#AssociationOverride(name = "pk.enterprise", joinColumns = #JoinColumn(name = "idEnterprise")) })

Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements

I have one lawyer table which is having id(int) as a primary key and Country table having country_code(String ) as a primary key. I want to create third table using #JoinTable annotation in hibernate with two foreign key in it. But when I run it following error is coming. Not sure how to map one string and one int as foreign keys in third table.
Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements: com.test.common.entities.Country.lawyer
This is my code
#Entity
#Table(name = "lawyer")
public class Lawyer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "lawyer_batch_no")
private int lawyerbatchNo;
#ManyToOne(targetEntity = Country.class, cascade = { CascadeType.ALL })
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") }, inverseJoinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") })
private Country country;
getter setter...
}
#Entity
#Table(name = "country")
public class Country {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "country_code")
protected String country_code;
#Column(name = "abbreviation")
protected String abbreviation;
#Column(name = "name", nullable = false)
protected String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "country")
protected Set<State> state = new HashSet<State>();
#OneToMany(targetEntity = Lawyer.class, cascade = { CascadeType.ALL }, orphanRemoval = true)
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") }, inverseJoinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") })
private Lawyer lawyer;
getter setter....
}
The error indicates that private Lawyer lawyer needs to be a collection as it's a #OneToMany relationship. In the Country class, the last relationship should be
#OneToMany(targetEntity = Lawyer.class, cascade = { CascadeType.ALL }, orphanRemoval = true)
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") }, inverseJoinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") })
private Set<Lawyer> lawyer;
// or a Collection/List/etc.

Order by using intermediate table column in JPA

I have Class Product (corresponding to PRODUCT table)
Class Product {
#Id
#Column(name = "PRODUCT_ID")
private Long id;
#Column(name = "NAME")
private String name;
//other attributes
}
I have another class Owner (corresponding to OWNER table)
Class Owner{
#Id
#Column(name = "OWNER_ID")
private Long id;
#Column(name = "NAME")
private String name;
}
I have an intermediate table named PRODUCT_OWNER (a product can have multiple owners).
The PRODUCT_OWNER table is something like this.
_______________________________________
| PRODUCT_ID | OWNER_ID | DISPLAY_ORDER |
|____________|__________|_______________|
Inside my Product class I have written a join statement to perform join using intermediate PRODUCT_OWNER table
#OneToMany(targetEntity = Owner.class, cascade = { CascadeType.ALL, CascadeType.MERGE }, fetch = FetchType.LAZY)
#JoinTable(name = "PRODUCT_OWNER",
joinColumns = { #JoinColumn(name = "PRODUCT_ID") },
inverseJoinColumns = { #JoinColumn(name = "OWNER_ID") })
private Set<Owner> productOwners = new HashSet<Owner>(0);
I have a column in my intermediate table as DISPLAY_ORDER. I want to sort the final Set productOwners using DISPLAY_ORDER. Is this possible in above approach. Please advice.
Hi you can try to add this to your JoinTable
#OneToMany(targetEntity = Owner.class, cascade = { CascadeType.ALL, CascadeType.MERGE }, fetch = FetchType.LAZY)
#JoinTable(name = "PRODUCT_OWNER",
joinColumns = { #JoinColumn(name = "PRODUCT_ID") },
inverseJoinColumns = { #JoinColumn(name = "OWNER_ID") })
#OrderColumn(name="DISPLAY_ORDER")
private List<Owner> productOwners = new HashSet<Owner>(0);

Categories