I'm having trouble with a one to many relationship. I have a user, user_company (relates a user to a company, a user can have several companies) and a user role (a user can have different roles in different companies). The problem is that the user role it's only loaded with the first user. If I test any other user the user role is null. It's really weird, I have 10 users and only the first one works. Here is the code:
User:
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 14)
#Column(name = "user_name")
private String userName;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 14)
#Column(name = "user_password")
private String userPassword;
#Size(max = 1)
#Column(name = "user_logged")
private String userLogged;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "userCompanyUserName")
private Collection<UserCompany> userCompanyCollection;
User Company:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "user_company_id")
private Integer userCompanyId;
#JoinColumn(name = "user_company_user_name", referencedColumnName = "user_name")
#ManyToOne(optional = false)
private Users userCompanyUserName;
#JoinColumn(name = "user_company_company", referencedColumnName = "company_id")
#ManyToOne(optional = false)
private Companies userCompanyCompany;
/*
#JoinColumns({
#JoinColumn(name = "user_company_user_roles", referencedColumnName = "user_role_id"),
#JoinColumn(name = "user_company_id", referencedColumnName = "user_role_company_id", insertable = false, updatable = false)
})*/
#JoinColumns({
#JoinColumn(name = "user_company_user_roles", referencedColumnName = "user_role_id"),
#JoinColumn(name = "user_company_id", referencedColumnName = "user_role_company_id", insertable = false, updatable = false)
})
#ManyToOne(optional = false)
private UserRoles userCompanyUserRoles;
User Roles:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "userCompanyUserRoles")
private Collection<UserCompany> userCompanyCollection;
private static final long serialVersionUID = 1L;
#EmbeddedId
protected UserRolesPK userRolesPK = new UserRolesPK();
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 50)
#Column(name = "user_role_name")
private String userRoleName;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 200)
#Column(name = "user_role_description")
private String userRoleDescription;
About the data:
I have 10 users, called: test1,test2,test3....
I have 10 records of user_company. They relate all the users to company1 and userrole1.
The data is basically the same for the 10, that's why I think is really weird that only test1 works.
Thanks in advance for all the help.
Regards,
Daniel
Enable logging a check the SQL generated. If it is correct, execute it directly on your database, see if you get the result you expect.
Do you create the data in your test, or is it existing? It could be you are corrupting your cache when creating the data. Ensure you correctly maintain your bi-directional relationships.
Related
enter image description here
I am trying to map some entities to tables in MySQL database using Spring Boot JPA. I have a problem with one of the tables because in that one too many foreign keys are added. I highlighted the columns in the picture. I suppose that the problem might be linked with the fact that the Tutorial table has either One to Many or Many to Many relations with the other 3 tables, but I am not sure
#Entity(name = "authors")
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "author_id")
private Long authorId;
#Column(name = "first_name", nullable = false, length = 100)
private String firstName;
#Column(name = "last_name", nullable = false, length = 100)
private String lastName;
#Column(name = "email", length = 320, unique = true)
private String email;
#Column(name = "job_title", length = 255)
private String jobTitle;
#Lob
#Type(type = "org.hibernate.type.BinaryType")
#Column(name = "profile_picture")
private byte[] profilePicture;
#Column(name = "about", length = 2000)
private String about;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "author_id")
private List<Tutorial> tutorials;
}
#Entity(name = "categories")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id")
private Long categoryId;
#Column(name = "category_name", nullable = false, unique = true, length = 100)
private String categoryName;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id")
private List<Tutorial> tutorials;
}
#Entity(name = "tutorials")
public class Tutorial {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "tutorial_id")
private Long tutorialId;
#Column(name = "tutorial_title", nullable = false, length = 150)
private String tutorialTitle;
#Column(name = "tutorial_description", nullable = false, length = 2000)
private String tutorialDescription;
#Column(name = "time_to_complete")
private Integer timeToComplete;
#Column(name = "date_published")
private Long datePublished;
#Column(name = "last_updated")
private Long lastUpdated;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "tutorials")
private List<User> users = new ArrayList<>();
#ManyToOne(fetch = FetchType.EAGER)
private Category category;
#ManyToOne(fetch = FetchType.EAGER)
private Author author;
}
Tutorials is the table where the problems appear as 4 foreign keys are generate instead of two
#Entity(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#Column(name = "first_name", nullable = false, length = 100)
private String firstName;
#Column(name = "last_name", nullable = false, length = 100)
private String lastName;
#Column(name = "user_name", nullable = false, unique = true, length = 100)
private String userName;
#Column(name = "age")
private Integer age;
#Column(name = "email", length = 320, unique = true)
private String email;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "users_tutorials",
joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "tutorial_id") })
private List<Tutorial> tutorials = new ArrayList<>();
}
Try this changes:
remove #JoinColumn(name = "author_id")from Author and place in Tutorial:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "author_id")
private Author author;
remove #JoinColumn(name = "category_id")from Category and place it in Tutorial as well:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "category_id")
private Author author;
To get more information look here: Baeldung - Hibernate One to Many
I have 2 tables project and employee have multiple relationship. Project has many employees, employee can join many projects( many to many). project have one employee whose is team leader, an employee can manager many projects(many to one). So how do I design database, and classes model mapping with database. Some one help me
This is my code
class user
#Entity(name = "USERS")
public class Users {
#Id
#Column(name = "USER_ID", length = 6)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer userId;
#Column(name = "USER_NAME", length = 50, nullable = false)
private String userName;
#Column(name = "PASS_WORD", length = 50, nullable = false)
private String passWord;
#Column(name = "FULL_NAME", length = 50, nullable = false)
private String fullName;
#Column(name = "EMAIL", length = 50, nullable = false)
private String email;
#Column(name = "PHONE", length = 11, nullable = true)
private String phone;
#Column(name = "STATUS", nullable = true)
private Boolean status;
#ManyToMany(fetch = FetchType.LAZY)
#JsonIgnore
#JoinTable(name = "USERPROJECT", joinColumns = { #JoinColumn(name =
"USER_ID") }, inverseJoinColumns = {
#JoinColumn(name = "PROJECT_ID") })
private List<Project> projects;
#OneToMany(mappedBy = "teamlead")
private List<Project> projectOfTeamLead;
//get set.....
}
class project
#Entity(name = "PROJECTS")
public class Project {
#Id
#Column(name = "PROJECT_ID", length = 6)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer projectId;
#Column(name = "PROJECT_NAME", length = 50, nullable=false)
private String projectName;
#Column(name = "USER_CREATE_ID", length = 6, nullable=false)
private Integer userCreateId;
// #Column(name = "TEAM_LEAD_ID", length = 6, nullable=false)
// private Integer teamLeadId;
#Column(name = "TIME_START", nullable=true)
private Date timeStart;
#Column(name = "TIME_END", nullable=true)
private Date timeEnd;
#ManyToMany(mappedBy = "projects")
private List<Users> users;
#ManyToOne
#JoinColumn(name = "TEAM_LEAD_ID")
private Users teamlead;
//get set...
}
I think you need to make your database fit into 3nf (third normal form). You are describing a database that uses two tables, but I think you need three at least, that way you can describe what employees are on what project. A "team" table that uses the PK's from the other two tables should be used. Conventionally, you would name it something like "ProjectEmployees" as it is comprised of the PK's from the "Projects" table and the "Employees" table respectively. I hope that answers your question. If you don't understand what I'm talking about, I highly recommend you watch this.
I have a database with several entities, in particular Book and User. Between them there exists a ManyToMany relationship like this:
Book:
#Entity
#Table(name = "Books")
public class Book implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "bookId", nullable = false, unique = true)
private Long id;
#Column(name = "title", nullable = false)
private String title;
#Column(name = "price", nullable = false)
private int price;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "User_Book",
joinColumns = #JoinColumn(name = "bookId"),
inverseJoinColumns = #JoinColumn(name = "userId"))
private Set<UserAccount> users;
User:
#Entity
#Table(name = "UserAccounts")
public class UserAccount implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "userId", nullable = false, unique = true)
private Long id;
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
private String password;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "User_Book",
joinColumns = #JoinColumn(name = "userId"),
inverseJoinColumns = #JoinColumn(name = "bookId"))
Set<Book> purchasedBooks;
Everything works fine, the table User_Book is indeed created in the database. The problem seems to be related to the access of this Table.
For example,
Query query = entityManager.createQuery("SELECT u FROM User_Book u");
keeps telling me the following:
The abstract schema type 'User_Book' is unknown
So, shall I create from scratch the User_Book entity? Will it get automtically populated like now, that is, whenever a user buys a book, will this purchase be recorded in the table?
User_Book is not an entity. Therefore you cannot use createQuery, BUT you can use createNativeQuery to execute a SQL query:
Query query = entityManager.createNativeQuery("SELECT * FROM User_Book");
The result will be List<Object[]>
Ok, so I'd like to implement a simple forum example. So, I have threads, messages and users, of course and these are the pojos (I omitted the usually getters and simplicity)
Message
#Entity
#Table(name = "message")
public class Message implements java.io.Serializable, RecognizedServerEntities
{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#Cascade({ CascadeType.SAVE_UPDATE })
#JoinColumn(name = "thread", nullable = false)
private Thread thread;
#ManyToOne(fetch = FetchType.LAZY)
#Cascade({ CascadeType.SAVE_UPDATE })
#JoinColumn(name = "author", nullable = true)
private User user;
#Column(name = "title", nullable = false, length = 31)
private String title;
#Column(name = "body", nullable = false, columnDefinition = "Text")
private String body;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "last_modified_date", nullable = false, length = 19)
private Date lastModifiedDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_date", nullable = false, updatable = false, length = 19)
private Date createdDate;
}
User
#Entity
#Table(name = "user", uniqueConstraints =
{ #UniqueConstraint(columnNames = "email"),
#UniqueConstraint(columnNames = "nick") })
public class User implements java.io.Serializable, RecognizedServerEntities
{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#Column(name = "email", unique = true, nullable = false, length = 31)
private String email;
#Column(name = "password", nullable = false, length = 31)
private String password;
#Column(name = "nick", unique = true, nullable = false, length = 31)
#NaturalId(mutable = false)
private String nick;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "registered_date", nullable = false, updatable = false, length = 19)
private Date registeredDate;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user", orphanRemoval = false)
private Set<Thread> threads = new HashSet<Thread>(0);
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user", orphanRemoval = false)
private /**transient /**/ Set<Message> messages = new HashSet<Message>(0);
}
Thread
#Entity
#Table(name = "thread")
public class Thread implements java.io.Serializable, RecognizedServerEntities
{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#Cascade({CascadeType.SAVE_UPDATE})
#JoinColumn(name = "parent_thread", nullable = true)
private Thread parentThread;
#ManyToOne(fetch = FetchType.LAZY)
#Cascade({CascadeType.SAVE_UPDATE})
#JoinColumn(name = "author", nullable = true)
private User user;
#Column(name = "title", nullable = false, length = 63)
private String title;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "last_modified_date", nullable = false, length = 19)
private Date lastModifiedDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_date", nullable = false, updatable = false, length = 19)
private Date createdDate;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "thread"/**/, orphanRemoval = true/**/)
#Cascade({ CascadeType.REMOVE })
private /**transient /**/ Set<Message> messages = new HashSet<Message>(0);
#OneToMany(fetch = FetchType.LAZY, mappedBy = "parentThread", orphanRemoval = true)
#Cascade({CascadeType.REMOVE })
private /**transient /**/ Set<Thread> subThreads = new HashSet<Thread>(0);
}
I have many doubts on the annotations of course, but these are the relevant choice.
When I delete an user, I don't want to delete all his threads and messages, so it make sense to don't use orphan-removal or cascade delete on the #OneToMany associations (ie the messages and threads collections).
Also, because the id is automatically generated from the database, I don't think it make sense at all to use the annotation CascadeType.UPDATE (or SAVE_UPDATE) on the collections of all the entity.
A thread are the most problematic entity to manage. When we delete a thread, we want that all its subthreads and all its messages were deleted. So, I use the CascadeType.REMOVE and orphan-removal annotations.
An all the #ManyToOne associations, I use the CascadeType.ALL. The idea is that if we delete a message or a subthread, all the parents will be updated.
All the collections are not transient.
Feel free to propose suggestion on this of course.
Btw, given the whole story, this is the question: suppose I have a thread "mThread" started from the user "mUser" with many messages from different users, how can I safely delete the user?
I tried different things, but I'm not sure of anything and in most cases I only have exceptions.
EDIT
I also have another class, StorageManager<T>, that is used to encapsulate the common code between entities. Basically, it implements the "one session per transaction" pattern. So each methodX() basically:
invoke sessionFactory.openSession() and session.beginTransaction()
invoke session.methodX()
invoke transaction.commit()
invoke session.clear() and session.close
Example with code
for (Thread t : mUser.getThreads())
{
t.setUser(null);
storageManagerThread.update(t);
}
for (Message m : mUser.getMessages())
{
m.setUser(null);
storageManagerMessage.update(t);
}
storageManagerUser.delete(mUser);
Until this point, all the table in the database have the right values. However, I don't know if it is the right way to proceed, because it leaves dirty collections.
Indeed, when at later point I try to execute some other options (e.g. update(mThread) or delete a message from mThread) a NullPointerException was thrown. Why is this? .
[using JPA, MySQL, MVC, Servlets, JSP]
If I read some data from database LEFT JOIN-ing three tables (inside method of DAO object) how should I format that result, so i can set it as request attribute (in servlet) and forwards to JSP page?
Entities(tables in db):
Post:
#Entity
#Table(name = "post")
public class Post implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "post_id", unique = true, nullable = false)
private Integer id;
#Column(name = "post_title", length=300, unique = false, nullable = false)
private String title;
#Column(name = "post_date", unique = false, nullable = false)
private Date date;
#Column(name = "post_summary", length=1000, unique = false, nullable = true)
private String summary;
#Column(name = "post_content", length=50000, unique = false, nullable = false)
private String content;
#Column(name = "post_visitors", unique = false, nullable = false)
private Integer visitors;
#ManyToOne
#JoinColumn (name = "user_id", referencedColumnName="user_id", nullable = false)
private User user;
#ManyToOne
#JoinColumn (name = "category_id", referencedColumnName="category_id", nullable = false)
private Category category;
#OneToMany(cascade = { ALL }, fetch = LAZY, mappedBy = "post")
private Set<Comment> comments = new HashSet<Comment>();
...
Entity Comment:
#Entity
#Table(name = "comment")
public class Comment implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "comment_id", unique = true, nullable = false)
private Integer id;
#Column(name = "comment_title", length=300, unique = false, nullable = false)
private String title;
#Column(name = "comment_date", unique = false, nullable = false)
private Date date;
#Column(name = "comment_content", length=600, unique = false, nullable = false)
private String content;
#ManyToOne
#JoinColumn (name = "user_id", referencedColumnName="user_id", nullable = false)
private User user;
#ManyToOne
#JoinColumn (name = "post_id", referencedColumnName="post_id", nullable = false)
private Post post;
...
Entity User:
#Entity
#Table(name = "user")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "user_id", unique = true, nullable = false)
private Integer id;
#Column(name = "user_name", length=45, unique = false, nullable = false)
private String name; // "first_name" + ' ' + "last_name"
//URL address to user's image
#Column(name = "user_image", length=500, unique = false, nullable = true)
private String image;
#Column(name = "user_username", length=45, unique = false, nullable = false)
private String username;
#Column(name = "user_password", length=45, unique = false, nullable = false)
private String password;
...
So, I would like to make a method, probably inside PostDAO object that will look something like this:
public <SomeDataTypeFormat???> getPostsSummaries(){
Query q = em.createNativeQuery("SELECT
post_title,
post_summary,
post_date,
COUNT(comment_id) AS comment_cnt,
user.user_name
FROM
post
LEFT JOIN user USING(user_id)
LEFT JOIN comment USING(post_id)
GROUP BY
post_id
ORDER BY
comment_cnt DESC");
...
}
Method returns some fields from all three tables in database.
Do I need to make separate class and store those data in objects of that class? Or JSON (although I haven't worked with it yet)?
What is the practice? What is easiest data format to use and forward from servlet to JSP, for some fields gotten as a result of joining couple tables?
It depends on your objective; to get the data to the browser, JSON and AJAX isn't a bad choice. To get the data to the JSP (from the Servlet), you'll probably want a Data Transfer Object (or possibly an immutable Value Object).