Reputation: 102
So I currently have a database with the user information and what defines the user is the user_id.
Then I have table named token, that has a token_id and user_id as the primary key and the rest of the information, making this a one to many database.
@Entity
@Table(name = "user")
public class User implements Serializable {
@Id
@Column(name = "user_id")
private long userId;
//Other variables and getters and setters
@OneToMany(orphanRemoval = true, mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@Access(AccessType.PROPERTY) //I need this as is since I have other things in the setter
private List<Token> tokens = new ArrayList<>();
public List<Token> getTokens() {
return tokens;
}
public void setTokens(List<Token> tokens) {
this.tokens = tokens;
}
}
After this snipped of code I have the token's class
public class Token implements Serializable{
@Id
private long tokenId;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@Column(nullable = false)
private String token;
@Access(AccessType.PROPERTY)
private Instant lastUsed;
@Column(nullable = false)
private Instant dateCreated;
@Transient
private boolean expired;
//Getters and setters go here
//Static methods and generating the token
private static String generateToken(){
Random random = new Random();
byte[] randomString = new byte[256];
random.nextBytes(randomString);
return Base64.encodeBase64String(randomString);
}
public static Token generateUserToken(User user){
Token token = new Token();
token.setTokenId(new Random().nextLong());
token.setUser(user);
token.setDateCreated(Instant.now());
token.setToken(generateToken());
return token;
}
//Static methods and generating the token
}
Now for some reason whenever the User user
is not marked as @Id it works (even if in the database it is a primary key).
Any help;
application.properties:
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL57InnoDBDialect
spring.jpa.show-sql=true
logging.level.org.hibernate.type=TRACE
SQL Output:
Hibernate: insert into tokens (date_created, last_used, token, user_id, token_id) values (?, ?, ?, ?, ?)
binding parameter [1] as [TIMESTAMP] - [2018-05-14T08:29:00.719764Z]
binding parameter [2] as [TIMESTAMP] - [null] //This is okay to be null this is last_used
binding parameter [3] as [VARCHAR] - [<Token too long to write in question>] //Actual data type is LONGTEXT
binding parameter [4] as [BIGINT] - [null] //this is a problem (user_id should not be - should be a long numebr such as: 5531405900210671089)
binding parameter [5] as [BIGINT] - [0] //this is a problem (token_id should be a long number such as: -8824825685434914749)
SQL Error: 1048, SQLState: 23000
Column 'user_id' cannot be null
Upvotes: 1
Views: 112
Reputation: 3276
This is a "derived identity", so Token
needs an @IdClass
like this:
public class TokenId implements Serializable {
private long tokenId; // matches the name of the attribute
private long user; // matches name of attribute and type of User PK
...
}
Then Token
needs to specify its @IdClass
like this:
@Entity
@IdClass(TokenId.class)
public class Token {
...
}
Derived identities are discussed (with examples) in the JPA 2.1 spec in section 2.4.1.
Upvotes: 1
Reputation: 1667
You do not need to annotate user_id with @Id in Token: you saw that this works. Also in the Database it is enough to define the Primary Key of the Table Tokenas being tokednId. Of course user_id must be set as Foreign Key that shall not be null.
Upvotes: 2