I have two entity classes User and Record related to user and record table, where the record table has a column for user_id. But the user table doesnot need to have a record_id, so that mappedBy is used. My entity class mapping is as follows:
#JsonInclude(Include.NON_NULL)
#Entity
public class Record{
#Id
#GeneratedValue
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="user_id")
private User user;
.....getters and setters
}
#JsonInclude(Include.NON_NULL)
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToOne(cascade = CascadeType.ALL, mappedBy="user")
private Record record;
....getters and setters
}
While an insert method, the functionality is like that both the tabes will be filled. The user table and record table is filled while insert method execution, except the user_id column in record table.
What may be the issue. Any help apprciated.
Related
I have two entities: Player and Team:
Player:
#Data
#Entity
public class Player {
#Column(nullable = false)
private String username;
#OneToOne
#JoinColumn(name = "team")
#JsonIgnore
private Team team;
}
Team:
#Entity
#Data
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToOne(fetch = FetchType.EAGER)
private User captain;
#OneToMany(fetch = FetchType.EAGER)
private List<User> players;
}
TeamRepository:
#Repository
public interface TeamRepository extends JpaRepository<Team, Long> {
}
I want to delete the whole Team from database using delete() method from JPA. Unfortunately when I do so, all Players are also deleted from my database. I only want to detach them from the Team.
Adding cascade = CascadeType.ALL/DELETE to Team and calling delete() method results in User entities deletion from database, and that's what I don't want to happen.
Adding cascade = CascadeType.DETACH to Team and calling delete() throws me a
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`32308008_localdb`.`users`, CONSTRAINT `FKhn2tnbh9fqjqeuv8ehw5ple7a` FOREIGN KEY (`team_id`) REFERENCES `team` (`id`))
exception and I have no idea why.
If someone have an idea how to delete Team entity and detach User from context but not from database I would be VERY thankful!
I have 2 tables, the first one is quite variable, the second one contains only constants:
USER.ID USER.NAME USER.USER_TYPE (FK on USER_TYPE.ID)
INT VARCHAR(64) INT(1)
----------------------------------
1 Alex 3
2 Jane 1
3 Carl 3
USER_TYPE.ID USER_TYPE.VALUE
INT(1) VARCHAR(64)
------------------------------
1 PENDING
2 REGISTERED
3 BANNED
4 ACTIVE
The foreign key USER.USER_TYPE is required and refering to a primary key USER_TYPE.ID in table USER_TYPE (one-to-one relation). Here is my mapping in Hibernate.
User.java
#Entity
#Table(name = "USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_TYPE")
private UserType userType;
}
UserType.java
#Entity
#Table(name = "USER_TYPE")
public class UserType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "VALUE")
private String value;
}
My goal is to keep the enumerated values in the database. How to map UserType's value instead of id to User and validate it? I want to pass the constant VALUE to the String instead of its ID.
private String userType;
The expected result of the first user would be:
User[id=1, name=Alex, userType=Banned]
User[id=2, name=Jane, userType=Pending]
User[id=3, name=Carl, userType=Banned]
My attempt was to use this annotation on definition of table twice with both colums switched
#SecondaryTable(name="USER_TYPE",
pkJoinColumns={#PrimaryKeyJoinColumn(name="ID", referencedColumnName="USER_TYPE")}
)
and get the VALUE with
#Column(table="USER_TYPE", name="VALUE")
private String UserType;
however it leads to the error
Unable to find column with logical name: USER_TYPE in org.hibernate.mapping.Table(USER) and its related supertables and secondary tables
First you need to change the relation from #OneToOne to #ManyToOne as UserType can be used by one or many User and User can have one and one UserType.
Secondly use referencedColumnName which references :
The name of the column referenced by this foreign key column.
So User entity will be:
#Entity
#Table(name = "USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_TYPE", referencedColumnName = "VALUE")
private UserType userType;
}
In UserType you should apply a unique constraint using #NaturalId to value field + do not provide its setter, to prevent duplicate values as It may lead to inconsistency:
#Entity
#Table(name = "USER_TYPE")
public class UserType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#NaturalId
#Column(name = "VALUE")
private String value;
}
Hope it solves the issue!
Enumerations could be simpler:
enum UserType {
PENDING,
REGISTERED,
BANNED,
ACTIVE
}
#Entity
#Table(name = "USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#javax.persistence.Enumerated
private UserType userType;
}
If you really need separated table and #OneToOne relation, you can use #Formula from Hibernate:
#Formula("(select ut.value from user_type ut where ut.ID = USER_TYPE)")
private String userType;
For this really special requirement you could use SecondaryTable annotation.
That is, you don't need UserType entity, but declare attribute userType as String in User entity with column mapping to the secondary table "USER_TYPE".
First of all, I suggest you use ManyToOne relation. and Not CascadeType.ALL if you are not planning update or delete on USER_TYPE table.
If you do not need adding new UserTypes frequently use enum for it. It will just work as you want.
Second solution: As long as fetch = FetchType.EAGER you can add A transient field and return value of UserType in getter.
I am Linking User table with the Application Access. Here one User can have access to many applications.
I have done the mapping successfully with the below piece of code.
User entity object:
#Entity
#Table(name = "USER_TBL", uniqueConstraints = { #UniqueConstraint(columnNames = "USER_NAME") })
public class User implements Serializable {
.....
#Id
#GeneratedValue
#Column(name = "USER_ID", unique = true, nullable = false)
private Integer userId;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<UserAppAssociation> userAssociatedApplications = new ArrayList<UserAppAssociation>();
Getter and setter for userAssociatedApplications
}
Application access object:
#Entity
#Table(name="APPLICATION_ASSOC_TBL")
public class UserAppAssociation implements Serializable{
#Id
#Column(name="user_id", unique=true, nullable=false)
private Integer userId;
#Column(name = "application_id")
private Integer appId;
#Column(name = "user_type_id")
private Integer userTypeId;
...
#ManyToOne
#JoinColumn(name="USER_ID",insertable=false,updatable=false)
private User user;
..
getters and setters
}
Issue:
I am getting the same values in the Application List ('userAssociatedApplications'). Though i have different values in the application access table, I get the same values in the list. The first row value is repeated in the list.
DB:
I have 'User' table and the mapping is with application access
User table: USER_TBL
Columns
user_id name phone
Application access table : APPLICATION_ASSOC_TBL
Columns
User_id application_id and User_type
Note - no primary key in this table
Sample data:
User_id application_id User_type
1 1 1
1 2 1
1 3 1
Issue: I am getting the first value 1,1,1 in the list thrice.
Expected: List should be with 3 different values
Kindly help. I am not sure whether i am missing anyting in the annotation mapping.
Looks like a problem with this
#Id
#Column(name="user_id", unique=true, nullable=false)
private Integer userId;
#ManyToOne
#JoinColumn(name="USER_ID",insertable=false,updatable=false)
private User user;
Try to use this mapping. Please, refer this as a guide for names and don't use unnecessary annotations
#Entity
#Table(name = "xxx_users", uniqueConstraints = { #UniqueConstraint(columnNames = "f_name") })
public class User {
#Id
#GeneratedValue
#Column(name = "f_id")
private Integer id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<UserAppAssociation> applications = new ArrayList<UserAppAssociation>();
}
#Entity
#Table(name="xxx_user_applications")
public class UserAppAssociation {
#Id
#GeneratedValue
#Column(name = "f_id")
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="fk_user")
private User user;
}
I am working on a basic example to test cascade delete operation but I am getting exception.
I have below entities:
Employee.java
#Entity
public class Employee {
#Id
#Column(name = "EMP_ID")
private long id;
private String name;
#OneToMany(mappedBy = "employee")
#Cascade(value = { CascadeType.REMOVE, CascadeType.SAVE_UPDATE })
private List<EmpDetails> details = new ArrayList<EmpDetails>();
}
EmpDetails.java
#Entity
public class EmpDetails {
#Id
private long id;
private int info;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "EMP_ID")
private Employee employee;
}
Now I have records in databse with employee id as 10 and corresponding records in employee details table.
Now when I run below query:
session.beginTransaction();
session.delete(new Employee(10)); // here 10 is the ID of the employee
session.getTransaction().commit();
session.close();
I was thinking hibernate will delete the employee record and the corresponding employee details records as I have set the cascade type to remove. But I am getting exception as :
Caused by:
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException:
Cannot delete or update a parent row: a foreign key constraint fails
Can someone please help me how to test the cascade delete option here?
The REMOVE cascade type is for the standard JPA remove() operation. For the native Hibernate delete() operation, you need to use a Hibernate-proprietary annotation:
#Cascade(CascadeType.DELETE)
When you delete Employee on session try to add this, I had the same issue:
session.delete(session.get(Employee.class, employee_Id));
On my issue I had Movie and TimeTable relation was OneToOne:
On Movie model:
public class Movie implements Serializable
{
#Id
#Column(name = "fid")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int fid;
....
#OneToOne(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private TimeTable timetable;
}
On TimeTable model:
public class TimeTable implements Serializable
{
...
#OneToOne
#JoinColumn(name = "fid")
private Movie movie;
}
I have been trying to fetch data from 2 different tables to a single entity in JPA but with no result.
The entity that keeps data from two different tables is as below :
#Data #Entity #JsonSnakeCase
public class WareHouse {
#Id
#GeneratedValue
private long id;
#Column(unique = true)
private String fcId;
#Enumerated(EnumType.STRING)
private FCStatus status;
#OneToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER, mappedBy = "fcId")
private List<WorkingHours> workingHours;
#Enumerated(EnumType.STRING)
private IntegrationType integrationType;
}
The other entity WorkingHours is :
#Data
#Entity
#JsonSnakeCase
public class WorkingHours {
#Id
#GeneratedValue
private long id;
private String fcId;
private LocalDate date;
private DateTime start;
private DateTime end;
}
The tables WareHouse and WorkingHours have one-to-many relationship and fcId is the column that joins them.
In my use case, I have to fetch WareHouse details and its WorkingHours in a single entity WareHouse as defined above. How do I achieve this ?
The named query (below) only fetches the WareHouse data and WorkingHours is coming empty. Is the data model wrong ? Or is the query wrong ? (I thought JPA would take care of automatically fetching from the related table when given the annotations OneToMany and FetchType etc.)
<named-query name="searchByFcId">
<query>
<![CDATA[
select f from WareHouse f where f.fcId = :fc_id
]]>
</query>
</named-query>
You can try the following mappings. The JPA 2.0 spec note (11.1.21) notes:
If the referencedColumnName element is missing, the foreign key is assumed to
refer to the primary key of the referenced table.
However it also goes on to note that:
Support for referenced columns that are not primary key columns of the
referenced table is optional. Applications that use such mappings
will not be portable.
So whether or not this works will depend on your provider.
Warehouse:
#Data
#Entity
#JsonSnakeCase
public class WareHouse {
#Id
#GeneratedValue
private long id;
#Column(unique = true)
private String fcId;
#Enumerated(EnumType.STRING)
private FCStatus status;
#OneToMany(mappedBy = "warehouse", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
private List<WorkingHours> workingHours;
#Enumerated(EnumType.STRING)
private IntegrationType integrationType;
}
WorkingHours:
#Data
#Entity
#JsonSnakeCase
public class WorkingHours {
#Id
#GeneratedValue
private long id;
#ManyToOne
#JoinColumn(name = "fcId", referencedColumnName="fcid")
private Warehouse warehouse;
private LocalDate date;
private DateTime start;
private DateTime end;
}