Schema-validation: missing table [game] - jpa

I think it may be possible dupplicate of this: Schema-validation: missing table [hibernate_sequences] but I can't figure it out.
So in my application.properties file I have this option: spring.jpa.hibernate.ddl-auto=validate and I receive this error:
Schema-validation: missing table [game]
Why I am receiving this?
Here is my Game class and User class:
Game:
#Entity
public class Game {
#Id
#Column(name = "GAME_NUMBER")
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long gameNumber;
private int playerScore;
private int NPCScore;
private Date datetime;
#ManyToOne
#JoinColumn(name="USER_ID")
private User user;
public Game() {}
public Game(int playerScore, int nPCScore, Date datetime) {
super();
this.playerScore = playerScore;
this.NPCScore = nPCScore;
this.datetime = datetime;
}
public User getUser() {
return user;
}
} + getters & setters
User:
#Entity
public class User {
#Id
#Column(name = "USER_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long userId;
private String username;
private String password;
#OneToMany(mappedBy="user",cascade=CascadeType.ALL)
private List<Game> games;
#ElementCollection
private List<Date> startSessions;
public User() {}
public User(String username, String password, List<Game> games, List<Date> startSessions) {
super();
this.username = username;
this.password = password;
this.games = games;
this.startSessions = startSessions;
}
}

validate validates that the entities are compatible against the target, to a degree it's not foolproof. Anyway, whatever database you are trying to validate against does not have a table called game in which to store the entities.
This answer goes into more detail about what validate does.
Hibernate - hibernate.hbm2ddl.auto = validate
specifically,
checks the presence of tables, columns, id generators
Without knowing your database/expectations (are you expecting it to be created, or using Flyway/Liquibase to create/update the database etc.) I can't answer if validate is correct for your use case.
You could try create-drop to create and drop the table on startup/shutdown, but this isn't a solution for any production control over a database.

I got the same as I changed to Hibernate 5.4.0.Final.
Either Hibernate suddenly has problems to recognize the default schema or the driver does not return the schema properly.
I was able to bypass it by either adding the schema definition to the table definition.
#Table(name = "GAME", schema = "PUBLIC")
or by adding a default schema in persistence.xml.
<property name="hibernate.default_schema" value="PUBLIC" />

Don't forget permissions:
GRANT select, insert, update, delete, alter ON table_name TO usr_name;

This error can appear while using spring boot with flywayDB.
The issue might be due to the wrong naming convention of script files, which were used by flywayDB.
https://flywaydb.org/documentation/migrations#naming

The SQL standard requires names stored in uppercase.
If you named the table/fields in lowercase - JPA can automatically convert case to upper and trying to search names in this case, but write to logs in lower ¯\_(ツ)_/¯

Add this in application.yml:
spring:
jpa:
properties:
hibernate:
default_schema: game

Hibernate version 5.6.9,
Case-sensitive implementation:
hibernate:
physical_naming_strategy: 'org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl'

Related

Load newest version of an entity with JPA

I have the following entities:
#Entity
public class Policy {
#ID
private String uuid;
private String policyId;
private Long version;
private Long auditVersion;
}
#Entity
public class PolicySearch {
#ID
private String uuid;
#ManyToOne(optional = false)
#JoinColumn(name = "policy_id", referencedColumnName = "policy_id")
private Policy policy;
}
Basically, I've got an insurance policy where all changes are tracked in the DB (auditVersion). After some smaller changes a version can be released, that's when version increments and auditVersion starts at 0 again. Each DB entry has a different UUID, but the insuranceId stays the same for all versions of one policy.
The problem: I've got an entity for searches, a search always searches all versions of a policy - that's why I reference the policyId and not the uuid. When JPA loads the entity I end up with any policy. I would like a way to always get the highest version of a policy given the referenced policyId (and the highest auditVersion of that version).
I've thought of the following ways, but I'm not happy with either of those:
Change the type of the referenced Policy from Policy to String and only save the policyId, this would work but I would still want the foreign key constraint and I can't seem to find a way to create it with a JPA annotation (JPA creates my DB schema).
Keep the entities as is but discard the loaded Policy in favor of the newest one after loading the PolicySearch. This could be done in the DAO but if any entities in the future have PolicySearch as a member this seems like a really bad idea.
Any help would be greatly appreciated. I use EclipseLink.
I tried to add constraints to the DB but Postgres won't let you add foreign key constraints for columns which are not unique. The solution (which a coworker of mine came up with) for us was to change the database design and create a new entity which holds the PolicyId. So our Entities now look like this:
#Entity
public class Policy {
#ID
private String policyId;
}
#Entity
public class PolicyVersion {
#ID
private String uuid;
private Policy policy;
private Long version;
private Long auditVersion;
}
#Entity
public class PolicySearch {
#ID
private String uuid;
#ManyToOne(optional = false)
#JoinColumn(name = "policy_id", referencedColumnName = "policy_id")
private Policy policy;
}
This basically solves all the problems and has some other benefits too (like easy queries).

How can I set foriegn key column in Spring JPA

I am using Spring JPA and want to set value to a foreign key column. Here is my entities and repository.
#Entity
public class Device {
#NotEmpty
#Id
private String deviceId;
#ManyToOne
#JoinColumn(name="userId", referencedColumnName="userId", insertable=false, updatable=false)
#NotFound(action=NotFoundAction.IGNORE)
private User user;
//Getters and setters
}
#Entity
public class User(){
#Id
private String userId;
private String userName;
//Getters and setters
}
public interface DeviceRepository extends PagingAndSortingRepository {
}
public class DeviceServiceImpl implements DeviceService {
#Autowired
private DeviceRepository devRepos;
#Autowired
private UserRepository userRepos;
#Override
public void saveDevice(Device device, String userId) {
User user = null;
if (userId!=null) {
user = userRepos.findOne(userid);
device.setUser(user);
}
deviceRepos.save(device);
}
}
The user exists in Device table but userId column in the table does not set the value. Please help me to fix the problem.
EDIT:
I removed insertable and updatable from the annotation and now it works.
#JoinColumn(name="userId", referencedColumnName="userId")
Then, this means I have to get user of the device from the User table whenever I save a device?
Because you set insertable and updatable to false for the user property in your Device class , it will cause the persistence provider to ignore this column (Device.userId) when generating SQL INSERT and UPDATE statement.
Just change them to true or remove them as their default values are already true.
Update :
this means I have to get user of the device from the User table
whenever I save a device?
In pure JPA , if you know the ID of the user , you can use EntityManager#getReference(User.class , aUserId) to get an User instance without actually querying from DB . But in Spring Data JPA , it seems that this method is not supported out of the box.

Cannot change colum names in JPA Eclipselink

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.

Mutually referential fields in Play

I am trying to model users with home directories in my system. I got the following model declarations:
#Entity
public class Directory extends Model {
public String name;
#ManyToOne public Directory parent;
#ManyToOne public User owner;
#OneToMany public Set<User> sharees;
}
#Entity
public class User extends Model {
#Unique #Column(unique=true) public String username;
public String password;
public Directory homeDirectory;
public User(String username, String password) {
this.username = username;
this.password = password;
this.homeDirectory = new Directory(username, null, this);
}
}
When I create a user and call .save(), I get an error (A javax.persistence.PersistenceException has been caught, org.hibernate.exception.GenericJDBCException: could not insert: [models.User]). Can anyone explain why?
Using fixtures, can I test this? I'd need to create forward references in my yaml file, but I'm not sure if that's possible.
Thanks,
Vincent.
The error is thrown because of a missing #OneToOne annotation for homeDirectory.
I assume you're creating a directory for each user. If that's the case, then you should also use CascadeType.ALL so these directories automatically get created/deleted when users get created/deleted.
And no Yaml does not support forward references,
so you'll have to work around that when using bidirectional relations.

EclipseLink: is it possible to add #OneToMany relationship to class on an #EmbeddedId property as foreign key?

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.