I'm having problems making #Column(name="example") working.
I've got a User class:
#Entity
public class User {
#Id
private String username;
....
}
A Role one:
#Entity
public class Role {
#Id
private String name;
....
}
That are in a ManyToMany relationship. So I created a RoleMembership:
#Entity
#IdClass(UserRolePK.class)
public class RoleMembership {
#Id
#ManyToOne
#PrimaryKeyJoinColumn(name="USERNAME")
private User user;
#Id
#ManyToOne
#PrimaryKeyJoinColumn(name="ROLE")
private Role role;
....
}
As you can see, the primary key is defined in UserRolePK:
public class UserRolePK{
#Id
#Column(name="ROLE")
private String role;
#Id
#Column(name="USERNAME")
private String user;
...
}
In this class I use #Column(name="USERNAME") and #Column(name="ROLE") to force its name to that string, but it's not working: JPA gives it the default names USER_USERNAME and ROLE_NAME (that are in TABLE_ID format).
Can anyone help me finding the mistake?
Thanks,
Andrea
EDIT:
I need to have three tables:
user (username (pk), password ....)
user_role (username, role_name)
role (name (pk), description)
I cannot change User definition in my model.
Remove all the annotations in UserRolePK and change your #PrimaryKeyJoinColumn annotations to #JoinColumn annotations.
Your usage of PrimaryKeyJoinColumn does not seem to make sense. I think you should be using just a #JoinColumn, or are you also mapping the columns as basics?
Perhaps include you complete class, and the DDL that is generated.
Related
I like to have a single table ADDRESS in the Database and multiple unrelated entities for example User, Office will have one to many relations with the Address entity. In a nutshell my Entities would looke like
#Entity
public class Address {
#Id
private long id;
#Column
private String entityType; // served as discriminator e-g User,Office ...
#Column
private long entityId; // served as foreign key
... other address columns
}
User Class
public class User {
#Id
private long id;
#OneToMany
private List<Adress> addresses;t
}
Office class
#Entity
public class Office {
#Id
private long id;
#OneToMany
private List<Adress> addresses;
}
I tried #Any of Hibernate but that's not helping with One-to-Many relations. It has either Many-to-One and Many-to-Many relationships. What is the best way to achieve this in JPA.
I have an entity Person with a relation to an other person (mentor). This person can be null. I thought just the Constraints.Required annotation forces my mentor to be set.
If I remove the ManyToOne annotation the mentor wont be connected.
#Entity
public class Person extends Model {
#Id
#Constraints.Required
#Formats.NonEmpty
public Integer id;
#ManyToOne
#Constraints.Required
public User user;
#Constraints.Required
public String firstName;
#Constraints.Required
public String lastName;
#ManyToOne
public Person mentor;
...
How can I have a person without a mentor?
The usage of the #ManyToOne annotation is actually "instructing" your JPA provider th think that the Person table/relation has a foreign key to it (this models the 1:n relation b/n persons to mentors and a foreign key can't be null) but from your question, I see your biz needs doesn't need a 1:n per se so simply remove the #ManyToOne annotation and on case a person does have a mentor , wire this relation manually in the JPA entity constructor or via setter method
I have a User class:
#Entity
public class User extends Model {
#Id
public Long id;
public String email;
public String name;
public String password;
}
and a driver class
#Entity
public class Driver extends Model {
#Id
public Long id;
#OneToOne (cascade = CascadeType.ALL)
#Column(unique = true)
public User user;
}
I want to make sure that the user_id is unique inside the Drivers table. But the code above does not enforce that. (I can create multiple drivers with the same user id).
Ideally, I do not want to add the #OneToOne relations in the User class because there are several different roles inside my app (e.g. driver, teacher, agent etc.) and I don't want to pollute user class with all those relations.
How can I achieve this?
I have tried this code on the model for me, and it worked. One thing to be noted, that you must use #OneToOne annotation to let the ORM knows that you have foreign key reference to other model.
The model look like following:
#Entity
// add unique constraint to user_id column
#Table(name = "driver",
uniqueConstraints = #UniqueConstraint(columnNames = "user_id")
)
public class Driver extends Model {
#Id
public Long id;
#OneToOne
#JoinColumn(name = "user_id")
public User user;
}
It will generate evolution script like this :
create table driver (
id bigint not null,
user_id bigint,
constraint uq_driver_1 unique (user_id), # unique database constraint
constraint pk_driver primary key (id)
);
So, with this method you can make sure that you will have unique user reference on driver table.
Additional Info
Because there is an additional constraint, that is not handled by framework but by the database applied on the model (such as the unique constraint), to validate the input or handling the occurred exception, you can surround Model.save() or form.get().save() expression (saving-the-model) with try-catch block to handle the PersistenceException.
I would like some advice on how to best layout my JPA entity classes. Suppose I have 2 tables I would like to model as entities, user and role.
Create Table users(user_id primary key,
role_id integer not null )
Create table role(role_id primary key,
description text,
)
I create the following two JPA Entities:
#Entity
#Table(name="users")
#Access(AccessType.PROPERTY)
public class User implements Serializable {
private Long userId;
private Long roleId;
private Role role;
#Column(name = "user_id")
#Id
public Long getUserId() {}
#Column(name = "role_id")
public Long getRoleId() {}
#ManyToOne()
JoinColumn(name="role_id")
public Role getRole() {}
}
Role Entity:
#Entity
#Table(name="Role")
#Access(AccessType.PROPERTY)
public class Role implements Serializable {
private String description;
private Long roleId;
#Column(name = "role_id")
#Id
public Long getRoleId() {}
#Column(name = "description")
public Long getDescrition(){}
#ManyToOne()
#JoinColumn(name="role_id")
public Role getRole() {}
}
Would the correct way to model this relationship be as above, or would I drop the private Long roleId; in Users? Any advice welcomed.
When I map it this way, I receive the following error:
org.hibernate.MappingException: Repeated column in mapping for entity:
Yes, you would drop the private Long roleId mapping when you have a #ManyToOne on the same column.
As the error implies, you can only map each column in an #Entity once. Since role_id is the #JoinColumn for the #ManyToOne reference, you cannot also map it as a property.
You can, however, add a convenience method to return the role ID, like
public Long getRoleId() {
return role.getId();
}
I want to do a Jaas login module using JPA to store my AuthUser and AuthUserRole. I'll focus on the JPA side on this question.
Here is what I would do in the Database (not at all legitimate SQL code but hopefully comprehensive):
TABLE AuthUser( INT uid, VARCHAR password )
PRIMARY KEY (uid)
TABLE AuthUserRole( INT uid, INT role )
PRIMARY KEY (uid , role)
FOREIGN KEY (uid) REFERENCE AuthUser.uid
It makes sense to me, one role can only be assigned to a user once.
Here is what I attempted to do in Java, not showing username and email in AuthUser:
#Entity
public class AuthUser {
#Id
private int uid;
private String password;
#OneToMany
private Set<AuthUserRole> roles;
}
#Entity
public class AuthUserRole {
#Embeddedid
private AuthUserRolePK authUserRolePK;
}
#Embeddable
public class AuthUserRolePK {
public int uid;
public int role;
}
Eclipselink does the mapping just fine, which means it works, but not the way I wanted. It makes a third table named *authuser_authuserrole* that holds the (AuthUser_uid , uid, role) columns. No need to mention AuthUser_uid and uid is identical.
The trivial answer would be:
#Entity
public class AuthUser {
#Id
private int uid;
private String password;
#OneToMany
#JoinColumn(name="authUserRolePK.uid", referencedColumnName="uid")
private Set<AuthUserRole> roles;
}
But EclipseLink cryes that when #Embeddedid is used, all primary key columns have to be mentioned.
Q: How do I make Eclipselink map my entities like the database schema I mentioned? Should I rather use #IdClass? I could see the result of a database --> entities mapping but that's too easy :)
Thank you for your answers!
Three tables is the typical way to do this actually, your approach is simply lacking a little bit of JPA finesse.
Typically you have three tables associated as follows:
AuthUser AuthUser_Role (association) Role
frank ---- frank,admin ----- admin
This is in fact what Eclipselink was trying to map for you, but in general, you don't create the AuthUser_Role mapping yourself. Instead, you create a field on AuthUser like:
#ManyToMany
Set<Roles> userRoles
And (optionally) on Role like:
#ManyToMany(mappedBy="userRoles")
Set<AuthUser> usersWithRole;
Then EclipseLink takes care of the join table for you, and all you need to worry about is the userRoles field, which will update the join.
You can extend this to create the join manually for say roles that start and end on a set date, etc, but for all but the most complex projects, that's usually not necessary, and can often be accomplished in a different way. For compliance purposes, it's easier to use one of the ELUG extensions to keep and access a history of changes for example, which is the most common reason I've seen for adding extra meta-data to the join information.
Alternatively, if you REALLY want to do this with only two tables, make the AuthUserRole the primary side, and the AuthUser the passive side.
#Entity
public class AuthUser {
#Id
private int uid;
private String password;
#OneToMany(mappedBy="user")
private Set<AuthUserRole> roles;
}
#Entity
public class AuthUserRole {
#Embeddedid
private AuthUserRolePK authUserRolePK;
}
#Embeddable
public class AuthUserRolePK {
public AuthUser user;
public int role;
}
In this arrangement, you will end up with only two tables, and the "user" field will indeed be equal to the uid of AuthUser in the database, it just shows up as an object on the Java side.