I need to create a join table in my database using JPA annotations so the result will be this:
So far I just implemented 2 entities:
#Entity
#Table(name="USERS", schema="ADMIN")
public class User implements Serializable {
private static final long serialVersionUID = -1244856316278032177L;
#Id
#Column(nullable = false)
private String userid;
#Column(nullable = false)
private String password;
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
#Entity
#Table(name="GROUPS", schema="ADMIN")
public class Group implements Serializable {
private static final long serialVersionUID = -7274308564659753174L;
#Id
#Column(nullable = false)
private String groupid;
public String getGroupid() {
return groupid;
}
public void setGroupid(String groupid) {
this.groupid = groupid;
}
}
Should i create another entity called USER_GROUP or i can just add some annotations, so the join table will be created automatically when i run create tables from entities(ORM)?
How should i annotate my entities to achieve the same as in the image?
You definitely shouldn't create User_Group entity as it's more the underlying database representation than the object oriented one.
You can achieve the join table by defining something like:
#Entity
#Table(name="USERS", schema="ADMIN")
public class User implements Serializable {
//...
#ManyToOne
#JoinTable(name="USER_GROUP")
Group group;
#Entity
#Table(name="GROUPS", schema="ADMIN")
public class Group implements Serializable {
//...
#OneToMany(mappedBy="group")
Set<User> users;
Edit: If you want to explicitly set the names of the columns you could use #JoinColumn elements as shown below:
#ManyToOne
#JoinTable(name="USER_GROUP",
joinColumns = #JoinColumn(name = "userid",
referencedColumnName = "userid"),
inverseJoinColumns = #JoinColumn(name = "groupid",
referencedColumnName = "groupid"))
Group group;
I would implement it this way:
#Entity
#Table(name="GROUPS", schema="ADMIN")
public class Group implements Serializable {
#OneToMany
#JoinTable(name = "USER_GROUP",
joinColumns = #JoinColumn(name = "groupid"),
inverseJoinColumns = #JoinColumn(name = "userid"))
private List<User> users;
}
Solution suggested by #PedroKowalski should work too, but then you'll have to keep a reference to Group entity in your User entity which is not always possible.
To have the same annotations like in your diagram you can do this in your User class:
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "USER_GROUP",
joinColumns = { #JoinColumn(name = "userid") },
inverseJoinColumns = { #JoinColumn(name = "groupid") })
private List<Group> grups;
in your group class
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "USER_GROUP",
joinColumns = { #JoinColumn(name = "groupid") },
inverseJoinColumns = { #JoinColumn(name = "userid") })
private List<User> users;
I'm wondering what is the point to create a Join Table in this way, considering that we can't access directly for queries?
JPA doesn't allow to make queries directly to the Join Table, so if the user want to do an operation on USER_GROUP, he has to creare a normal join query between users and groups; due to this, the join table USER_GROUP is useless.
Related
I have to Models for two Entities in Database. Model User and Model Role. These two entities have a many-to-many relationship. In the model files I have class User.java:
#Entity
#Table(name = "User")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String username;
private String password;
private String name;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "role_user",
joinColumns = {#JoinColumn(name = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "role_id")})
private Set<Role> roles;
//getters and setters
}
and I have class Role.java:
#Entity
#Table(name = "Role")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private int id;
private String role;
#ManyToMany(mappedBy = "roles", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<User> users;
//getters and setters
}
I also have the repositories/DAO for them:
public interface UserRepository extends JpaRepository<User, Integer>{}
and
public interface RoleRepository extends JpaRepository<Role, Integer> {}
Now when I fetch all results from class Role it returns all the columns from Entity User, how can I specify that I want only the column name from User Entity? Should I build another model only with the columns I need or there is any simple way to select specific columns?
I'm making an app that holds a UserProfile with Wallet that has many Transactions.
Here's the Transaction class:
#Entity
#Table(name = "transactions")
public class Transaction extends BaseEntity {
#Column(name = "amount", nullable = false)
private BigDecimal amount;
#Column(name = "executed_on", nullable = false)
private LocalDateTime executedOn;
#Column(name = "is_top_up")
private boolean isTopUp;
#Column(name = "note")
private String note;
#ManyToOne(targetEntity = UserProfile.class)
private UserProfile sender;
#ManyToOne(targetEntity = UserProfile.class)
private UserProfile receiver;
public Transaction() {
}
Here's the Wallet class
#Entity
#Table(name = "wallets")
public class Wallet extends BaseEntity {
#ManyToMany(targetEntity = Transaction.class, cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}, fetch = FetchType.EAGER)
#JoinTable(name = "wallets_transactions",
joinColumns = #JoinColumn(name = "wallet_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "transaction_id", referencedColumnName = "id")
)
private Set<Transaction> transactions;
public Wallet() {
this.transactions = new HashSet<>();
}
public Set<Transaction> getTransactions() {
return transactions;
}
public void setTransactions(Set<Transaction> transactions) {
this.transactions = transactions;
}
public void addTransaction(Transaction transaction) {
this.transactions.add(transaction);
}
}
What I want is, to get all transactions by sender and receiver search criteria. For example, user 'A' sent money to user 'B'. I'm using JpaRepository. The end result should be in a Page<Transaction> class.
So far, when using just findAllBySender(UserProfile sender, Pageable pageable), it does work and I get the exact right Transactions. But when I try Page<Transaction> findAllBySenderAndReceiver(UserProfile sender, UserProfile receiver, Pageable pageable); I get a Page<T> with 0 elements when my DB has test data with at least 1 record.
Solved. Turns out, I had a logical error. Thank you all, for your assistance.
My MySql tables:
db tables
And My Two Entity Classes are
#Entity
public class Tweet {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="tweet_id")
private int tweetId;
private String message;
private Date created;
#ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#JoinColumn(name="user_id")
private Person person;
...
}
#Entity
public class Person {
#Id
#Column(name = "user_id")
private String userId;
private String password;
private String email;
private String fullName;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "following", joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "following_id") })
private List<Person> following = new ArrayList<Person>();
...
}
Now I want to display messages of user praveen, and also all the messages mapped to praveen user in the following table. That means praveen user have 2 messages and his following users have 2 messages . Total 4 messages should be displayed. I really don't know how to retrieve this info using any technique in Hibernate. Please help me
I have three tables: users(id, name, login, password), roles(id, name), user_roles(id, user_id, role_id)
This is my code
#Entity
#Table(name = "users")
public class User extends Model {
#Id
public Long id;
public String name;
public String login;
public String password;
#ManyToMany
#JoinTable(
name = "user_roles",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id")
)
public Set<Role> roles;
public static Finder<Integer, User> find = new Finder<>(User.class);
}
#Entity
#Table(name = "roles")
public class Role extends Model {
#Id
public Long id;
public String name;
#ManyToMany(mappedBy = "roles")
public List<User> users;
public static Finder<Integer, Role> find = new Finder<>(Role.class);
}
I want to display all users with roles, example: {"id":1, "name":"My Name", "login":"My Login", "password":"My Password", roles: [{"name":"ADMIN"}, {"name":"USER"}]}
How can I do this? I'm new in Ebean and ORM. Thanks for any help.
Update
public Result all() {
List<User> users = User.find.all();
return ok(toJson(users));
}
But now I getting stackoverflow error infinite recursion.
Make users.role = null and then return Json
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();
}