How to configure Spring Boot one to many entity relationship - java

In my rest API, I have Role and RolePrivilege entities with #Entity annotation. There are some columns in each entity. I need to set a one-to-many relationship with these two. One role has many role privileges and one role privilege can only have one role. In my DB script file, I set it as
-- -----------------------------------------------------
-- Table `wdc`.`role`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `wdc`.`role` (
`roleId` INT NOT NULL AUTO_INCREMENT ,
`roleName` VARCHAR(45) NOT NULL ,
`disabled` INT(1) ZEROFILL NULL ,
PRIMARY KEY (`roleId`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `wdc`.`rolePrivileges`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `wdc`.`rolePrivileges` (
`privilegeId` INT NOT NULL AUTO_INCREMENT ,
`privilegeDescription` VARCHAR(45) NOT NULL ,
`roleId` INT NULL ,
`disabled` INT(1) ZEROFILL NULL ,
`lastModifiedUser` VARCHAR(30) NULL DEFAULT NULL,
`lastModifiedDateTime` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`privilegeId`),
FOREIGN KEY (`roleId`)
REFERENCES `wdc`.`role` (`roleId`)
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
This creates database fine. I created Role entity as follows,
#Entity
#Table(name = "role", schema = "wdc", catalog = "")
public class Role implements Serializable {
#Id
#Column(name = "roleid", nullable = false, unique = true)
#GeneratedValue(strategy=GenerationType.IDENTITY)
#OneToMany(mappedBy = "role", cascade = CascadeType.ALL)
private Set<RolePrivilege> rolePrivileges;
public Role(int roleId, String roleName, Integer disabled, RolePrivilege rolePrivileges) {
this.roleId = roleId;
this.roleName = roleName;
this.disabled = disabled;
this.rolePrivileges = Stream.of(rolePrivileges).collect(Collectors.toSet());
this.rolePrivileges.forEach(x -> x.setRoleId(this));
}
}
RolePrivilege entity as follows,
#Entity
#Table(name = "roleprivileges", schema = "wdc", catalog = "")
public class RolePrivilege implements Serializable {
#Id
#Column(name = "privilegeid")
#GeneratedValue(strategy = GenerationType.IDENTITY)
#ManyToOne
#JoinColumn
private Role role;
public RolePrivilege(int privilegeId, String privilegeDescription, Integer disabled, String lastModifiedUser, Timestamp lastModifiedDateTime) {
this.privilegeId = privilegeId;
this.privilegeDescription = privilegeDescription;
this.disabled = disabled;
this.lastModifiedUser = lastModifiedUser;
this.lastModifiedDateTime = lastModifiedDateTime;
}
}
I used CrudRepository interface to save new entries to database.
#Repository
public interface RoleRepository extends CrudRepository<Role, Integer> {
}
#Repository
public interface RolePrivilegeRepository extends CrudRepository<RolePrivilege, Integer> {
}
This is my service file for add new role privilege,
// ---------------------------------
// add new role privilege
// ---------------------------------
public String addRolePrivilege(RolePrivilege rolePrivilege){
try {
rolePrivilegesRepository.save(rolePrivilege);
return "Saved";
} catch (Exception e){
return "Failed";
}
}
As last I used Controller file as this,
// ---------------------------------
// add new role privilege to database
// ---------------------------------
#PostMapping(path = "/")
public #ResponseBody String addRolePrivilege(#RequestBody RolePrivilege rolePrivilege){
return rolePrivilegesService.addRolePrivilege(rolePrivilege);
}
But still when I trying to save new role privilege it saves with out roleId in rolePrivilege table.
I tried it this way,
{
"privilegeDescription": "add user",
"role": [
{
"roleId": "1",
"roleName": "user1",
"disabled": 0
}
],
"disabled": 0,
"lastModifiedUser": "1",
"lastModifiedDateTime": "2020-03-11T17:58:14.361+0000"
}
Where do I need to change? Please help me.
When I send request to save new role privilege it returns saved but when I check it with mysql workbench, the roleId column in emplty.

You have a raw #JoinColumn in RolePrivilege, change it, so that the name of the column is configured: #JoinColumn(name = "roleId").
Also you're saving RolePrivilege, but the changes are not cascading, change the mapping to:
#ManyToOne(cascade = CascadeType.ALL)
P.S.: Prefer Lists over Sets in -to-many mapping for performance reasons.

Firstly, do not return String(wrap it to class for example to RolePriviligueResponse with String status as response body), secondly you dont need #ResponseBody annotation, your #PostMapping annotation already has it, third - dont use Integer for ID, better use Long type.
And you did not provide the name of #JoinColumn(name="roleId")

Related

#OneToOne Relationship Spring Data JPA/Hibernate Entity Relationship

I'm working on adding a feature to an already developed spring boot web application. The primary entity that has child entities is a Record. It has a few columns/variables that I want to now be in its own, separate entity (CustomerOrder) and exist in a one-to-one relationship with the Record. To summarize:
Record {
thing 1
thing 2
thing 3
}
is now becoming:
CustomerOrder {
thing 1
thing 2
thing 3
}
Record {
CustomerOrder
}
I'm having some issues with what I've produced. Here is the CustomerOrder model's relevant relationship data:
#Entity
#Table(name="customer_orders")
public class CustomerOrder {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
... other columns
#OneToOne(orphanRemoval = true, cascade = CascadeType.ALL, mappedBy="customerOrder", fetch = FetchType.EAGER)
private Record record;
}
And then here is the Record model's relevant data:
#Entity
#Table(name="records")
public class Record extends Auditable<String> implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
... other columns
#OneToOne
#JoinColumn(name="customer_order_id", nullable = false, unique = true)
private CustomerOrder customerOrder;
}
My issue exists when I try to POST a record, when a user tries creating one in the ui. Here is the POST method for a record:
#PostMapping
public ResponseEntity<?> saveRecord(#RequestBody Record recordBody, BindingResult result) {
if(!result.hasErrors()) {
if(recordBody.getHardwareItems().isEmpty()) {
record = recordsService.save(recordBody);
} else {
// Save the record first, recordId is required on hardwareItems
// TODO: investigate Spring Hibernate/JPA rules - is there a way to save parent before children to avoid a null recordId
CustomerOrder customerOrder = recordBody.getCustomerOrder();
recordBody.setCustomerOrder(new CustomerOrder());
customerOrder.setRecord(record);
customerOrder = customerOrdersService.save(customerOrder);
record = recordsService.save(recordBody);
}
} else {
return new ResponseEntity<>(result.getAllErrors(), HttpStatus.BAD_REQUEST);
}
// Return the location of the created resource
uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{recordId}").buildAndExpand(record.getId()).toUri();
return new ResponseEntity<>(uri, HttpStatus.CREATED);
}
The error I receive is the following:
2021-02-19 00:46:28.398 WARN 29990 --- [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1364, SQLState: HY000
2021-02-19 00:46:28.398 ERROR 29990 --- [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : Field 'record_id' doesn't have a default value
This makes sense to me at least, since I'm trying to save the CustomerOrder object that depends on a Record object, which has yet to have been persisted. So, how do I go about changing up the order and/or creating and persisting a Record object so that I can then save the CustomerOrder object to it?
You need to mark your column record_id as AI(AUTO_INCREMENT) in your table definition.
ALTER TABLE records CHANGE record_id INT(6) NOT NULL AUTO_INCREMENT;
Your primary key is record_id, add #Column(name = "record_id", nullable = false)
#Entity
#Table(name="records")
public class Record extends Auditable<String> implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "record_id", nullable = false)
private Long id;
... other columns
#OneToOne
#JoinColumn(name="customer_order_id", nullable = false, unique = true)
private CustomerOrder customerOrder;
}

Error accessing field by reflection for persistent property [model.Credentials#email] on #EmbeddedID

I've been experiencing problems implementing the Authorities on my spring boot application, and after digging a little I realised that maybe the association between my Credentials and Authorities tables, was wrong.
In fact it come to my attention that Spring allowed every type of user, (regardless their authority) to access ever method, even the ones I though have been secured. At that point, I implemented a .findAll() method to actually see if there was some kind of problem on the association, and indeed there was.
Let me show first the MySQL tables:
CREATE TABLE credentials (
credential_id bigint UNSIGNED PRIMARY KEY AUTO_INCREMENT,
email varchar(50) NOT NULL UNIQUE,
password varchar(255) NOT NULL,
enabled BOOLEAN NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE authorities (
email varchar(50) NOT NULL,
authority varchar(50) NOT NULL,
PRIMARY KEY (email, authority),
CONSTRAINT fk_authorities_credentials FOREIGN KEY(email) REFERENCES credentials(email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Before jumping onto the associations in the entities, it's worth noting that the authorities entity has and embedded key reflecting the design of the table. So the email column its a foreign key and a primary at the same time:
#Embeddable
public class AuthoritiesKey implements Serializable {
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "email", nullable = false
,referencedColumnName = "email")
private Credentials credentials;
#JoinColumn(name = "authority", nullable = false)
private String authority;
//getters setters omitted
}
Credentials class:
#Entity
#Table(name = "credentials")
public class Credentials implements Serializable {
#OneToOne(cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "ak.credentials")
private Authorities authorities;
//other fields and getters/setters omitted
}
Removing the bilateral association (thus leaving it just on the AuthoritiesKey class), hibernate successfully returns all the credentials (without their authorities of course), and all the authorities (this time preceded by the credentials).
I cannot wrap my head around it.
The complete meaningful stack trace i get when I leave the bilateral association is the following:
Error accessing field [private java.lang.String com.server.model.Credentials.email] by reflection for persistent property [com.servermodel.Credentials#email] : 64;
nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private java.lang.String com.server.model.Credentials.email] by reflection for persistent property [com.server.model.Credentials#email] : 64
Where 64 is the id of the (last, but get called first) row in the Credential table.
=== UPDATE ===
public class CredentialsService implements UserDetailsService {
#Autowired
private CredentialsRepository cr;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Credentials user = cr.findByEmail(email);
if (user == null){
throw new UsernameNotFoundException(email);
}
return new UserPrincipal(user);
}
}
It looks like you can not use #OneToOne here due to the hibernate bug. (See HHH-3824) It's reproduced even with Hibernate 5.4.28.Final
As workaround, I would suggest you to correct your mapping in this way:
#Entity
#Table(name = "authorities")
public class Authorities {
#EmbeddedId
private AuthoritiesKey pk;
// ...
}
#Embeddable
public class AuthoritiesKey implements Serializable {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "email", referencedColumnName = "email", nullable = false)
private Credentials credentials;
#Column(name = "authority", nullable = false)
private String authority;
public AuthoritiesKey(Credentials credentials, String authority) {
this.credentials = credentials;
this.authority = authority;
}
public AuthoritiesKey() {
}
// getters setters omitted
#Override
public boolean equals(Object o) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
AuthoritiesKey pk = (AuthoritiesKey) o;
return Objects.equals( credentials, pk.credentials ) &&
Objects.equals( authority, pk.authority );
}
#Override
public int hashCode() {
return Objects.hash( credentials, authority );
}
}
#Entity
#Table(name = "credentials")
public class Credentials implements Serializable {
#Id
#Column(name = "credential_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "pk.credentials")
private List<Authorities> authorities;
#NaturalId
#Column(name = "email")
private String email;
#Transient
public Authorities getAuthority()
{
return this.authorities != null && this.authorities.size() > 0
? this.authorities.get(0) : null;
}
// ...
}

integrity constraint violation: unique constraint or index violation on Foreign key HSQL

I'm testing the underlying model of a HSQL database using Hibernate/Spring Boot and I've run into an issue I cannot find a solution to.
This is my simple test, I'm trying to create a shoebox entity and save it to the database with a User object set as the FK for Owner:
#TestConfiguration
static class ShoeboxServiceTestContextConfiguration {
#Bean
public ShoeboxService shoeboxService() {
return new ShoeboxService();
}
#Bean
public UserService userService() {
return new UserService();
}
}
#Autowired
UserService users;
#Autowired
ShoeboxService shoeboxes;
#Test
public void testSave()
{
System.out.println("save");
int userId = 1;
User user = new User(userId, "Foo", "hello#world.com");
user = users.save(user);
Shoebox sb = new Shoebox(user, "Name", "Context", "Comment", false);
UUID sbId = shoeboxes.save(sb).getId();
sb = shoeboxes.findOne(sbId);
assertNotNull(sb);
assertEquals(sb.getName(), "Name");
assertEquals(sb.getContext(), "Context");
assertEquals(sb.getComment(), "Comment");
assertEquals(sb.isShare(), false);
shoeboxes.deleteById(sbId);
users.deleteById(userId);
}
However when it gets it throws a
integrity constraint violation: unique constraint or index violation; SYS_PK_10126 table: USER
exception when it tries to save the Shoebox to the DB. It successfully persist the User, and it succeeds in persisting the Shoebox object when there is no Owner FK attached to it, but crashes when the FK is supplied.
Here is my User POJO:
#Entity
#Table(name="User")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class User implements Serializable
{
#Id
#Column(name = "ID")
private long ID;
#Column(name = "Name")
private String name;
#Column(name = "Email")
private String email;
#OneToOne(fetch = FetchType.LAZY)
private Shoebox currentlySelectedBox;
#OneToMany(fetch = FetchType.LAZY)
#JsonManagedReference(value="shoebox_owner")
private List<Shoebox> shoeboxes;
// Contructors, Getters/Setters etc.
}
And my Shoebox POJO:
#Entity
#Table(name="Shoebox")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Shoebox implements Serializable
{
#Id
#Column(name="ID")
UUID ID;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="OwnerID")
#JsonBackReference(value="shoebox_owner")
User owner;
#Column(name="Name")
String name;
#Column(name="Context")
String context;
#Column(name="Comment")
String comment;
#Column(name="Shared")
boolean share;
#Column(name="CreationDate")
LocalDateTime creationDate;
// Contructors, Getters/Setters etc.
}
Here is the HSQL creation script for the DB:
CREATE MEMORY TABLE PUBLIC.SHOEBOX(ID BINARY(255) NOT NULL PRIMARY KEY,COMMENT VARCHAR(255),CONTEXT VARCHAR(255),CREATIONDATE TIMESTAMP,NAME VARCHAR(255),SHARED BOOLEAN,OWNERID BIGINT)
CREATE MEMORY TABLE PUBLIC.USER(ID BIGINT NOT NULL PRIMARY KEY,EMAIL VARCHAR(255),NAME VARCHAR(255),CURRENTLYSELECTEDBOX_ID BINARY(255),CONSTRAINT FK3T924ODM2BIK5543K0E3UEGP FOREIGN KEY(CURRENTLYSELECTEDBOX_ID) REFERENCES PUBLIC.SHOEBOX(ID))
CREATE MEMORY TABLE PUBLIC.USER_SHOEBOX(USER_ID BIGINT NOT NULL,SHOEBOXES_ID BINARY(255) NOT NULL,CONSTRAINT FK5W8WMFC5E9RMEK7VC4N76MQVQ FOREIGN KEY(SHOEBOXES_ID) REFERENCES PUBLIC.SHOEBOX(ID),CONSTRAINT FKIR9SOKRCOQ33LCQTNR0LDXO93 FOREIGN KEY(USER_ID) REFERENCES PUBLIC.SHOEBOXUSER(ID),CONSTRAINT UK_508XA86IDIHP04FQD3D6GF8D7 UNIQUE(SHOEBOXES_ID))
ALTER TABLE PUBLIC.SHOEBOX ADD CONSTRAINT FK3J9RQBYW5VQ0IRF3FWYPG7LAB FOREIGN KEY(OWNERID) REFERENCES PUBLIC.USER(ID)
Why is the exception being triggered? Is there something wrong with my annotations and PK/FK relationships between the objects?
Many Thanks.
The issue is
#ManyToOne(cascade = CascadeType.ALL)
With CascadeType.ALL, any operations will extend to the other entities. So in this case the save method is cascading on the shoebox's user attempting to save it again. Since you are using a static id of 1, it is causing a key constraint.

Hibernate #Any annotation usage

I have one entity called Change where I need log changes in database like inserting, updating or deleting rows.
So my Change table contains some data and now I would like to add foreign key to record changes in another table, but I have different tables. For example I have Weather table, Group table,... So I have done some searching and I have found a little bit about #Any annotation. So I added some columns to my Change entity:
#Entity
#Table(name = "CHANGE")
public class Change {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CHANGE_ID")
private int changeId;
...
#Any(metaColumn = #Column(name = "RECORD_TABLE"))
#AnyMetaDef(idType = "int", metaType = "string",
metaValues = {
#MetaValue(targetEntity = Weather.class, value = "WEATHER"),
#MetaValue(targetEntity = Group.class, value = "GROUP"),
...
})
#JoinColumn(name="recordID")
private Object record;
#ManyToOne
#JoinColumn(name = "USER_ID")
private User user;
public Object getRecord() {
return record;
}
public void setRecord(Object record) {
this.record = record;
}
...
And my stupid question is:
How can I insert data into database (like foreign ID and class name) and how could I retrieve them?
Please go through this Link
You should care about your entity relationship (1-1 or 1-M or M-M)

OneToOne between two tables with shared primary key

I'm trying to set up the following tables using JPA/Hibernate:
User:
userid - PK
name
Validation:
userid - PK, FK(user)
code
There may be many users and every user may have max one validation code or none.
Here's my classes:
public class User
{
#Id
#Column(name = "userid")
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long userId;
#Column(name = "name", length = 50, unique = true, nullable = false)
protected String name;
...
}
public class Validation
{
#Id
#Column(name = "userid")
protected Long userId;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn(name = "userid", referencedColumnName = "userid")
protected User user;
#Column(name = "code", length = 10, unique = true, nullable = false)
protected String code;
...
public void setUser(User user)
{
this.user = user;
this.userId = user.getUserId();
}
...
}
I create a user and then try to add a validation code using the following code:
public void addValidationCode(Long userId)
{
EntityManager em = createEntityManager();
EntityTransaction tx = em.getTransaction();
try
{
tx.begin();
// Fetch the user
User user = retrieveUserByID(userId);
Validation validation = new Validation();
validation.setUser(user);
em.persist(validation);
tx.commit();
}
...
}
When I try to run it I get a org.hibernate.PersistentObjectException: detached entity passed to persist: User
I have also tried to use the following code in my Validation class:
public void setUserId(Long userId)
{
this.userId = userId;
}
and when I create a validation code I simply do:
Validation validation = new Validation();
validation.setUserId(userId);
em.persist(validation);
tx.commit();
But then since User is null I get org.hibernate.PropertyValueException: not-null property references a null or transient value: User.code
Would appreciate any help regarding how to best solve this issue!
I have been able to solve this problem of "OneToOne between two tables with shared primary key" in pure JPA 2.0 way(Thanks to many existing threads on SOF). In fact there are two ways in JPA to handle this. I have used eclipselink as JPA provider and MySql as database. To highlight once again no proprietary eclipselink classes have been used here.
First approach is to use AUTO generation type strategy on the Parent Entity's Identifier field.
Parent Entity must contain the Child Entity Type member in OneToOne relationship(cascade type PERSIST and mappedBy = Parent Entity Type member of Child Entity)
#Entity
#Table(name = "USER_LOGIN")
public class UserLogin implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="USER_ID")
private Integer userId;
#OneToOne(cascade = CascadeType.PERSIST, mappedBy = "userLogin")
private UserDetail userDetail;
// getters & setters
}
Child Entity must not contain an identifier field. It must contain a member of Parent Entity Type with Id, OneToOne and JoinColumn annotations. JoinColumn must specify the ID field name of the DB table.
#Entity
#Table(name = "USER_DETAIL")
public class UserDetail implements Serializable {
#Id
#OneToOne
#JoinColumn(name="USER_ID")
private UserLogin userLogin;
// getters & setters
}
Above approach internally uses a default DB table named SEQUENCE for assigning the values to the identifier field. If not already present, This table needs to be created as below.
DROP TABLE TEST.SEQUENCE ;
CREATE TABLE TEST.SEQUENCE (SEQ_NAME VARCHAR(50), SEQ_COUNT DECIMAL(15));
INSERT INTO TEST.SEQUENCE(SEQ_NAME, SEQ_COUNT) values ('SEQ_GEN', 0);
Second approach is to use customized TABLE generation type strategy and TableGenerator annotation on the Parent Entity's Identifier field.
Except above change in identifier field everything else remains unchanged in Parent Entity.
#Entity
#Table(name = "USER_LOGIN")
public class UserLogin implements Serializable {
#Id
#TableGenerator(name="tablegenerator", table = "APP_SEQ_STORE", pkColumnName = "APP_SEQ_NAME", pkColumnValue = "USER_LOGIN.USER_ID", valueColumnName = "APP_SEQ_VALUE", initialValue = 1, allocationSize = 1 )
#GeneratedValue(strategy = GenerationType.TABLE, generator = "tablegenerator")
#Column(name="USER_ID")
private Integer userId;
#OneToOne(cascade = CascadeType.PERSIST, mappedBy = "userLogin")
private UserDetail userDetail;
// getters & setters
}
There is no change in Child Entity. It remains same as in the first approach.
This table generator approach internally uses a DB table APP_SEQ_STORE for assigning the values to the identifier field. This table needs to be created as below.
DROP TABLE TEST.APP_SEQ_STORE;
CREATE TABLE TEST.APP_SEQ_STORE
(
APP_SEQ_NAME VARCHAR(255) NOT NULL,
APP_SEQ_VALUE BIGINT NOT NULL,
PRIMARY KEY(APP_SEQ_NAME)
);
INSERT INTO TEST.APP_SEQ_STORE VALUES ('USER_LOGIN.USER_ID', 0);
If you use Hibernate you can also use
public class Validation {
private Long validationId;
private User user;
#Id
#GeneratedValue(generator="SharedPrimaryKeyGenerator")
#GenericGenerator(name="SharedPrimaryKeyGenerator",strategy="foreign",parameters = #Parameter(name="property", value="user"))
#Column(name = "VALIDATION_ID", unique = true, nullable = false)
public Long getValidationId(){
return validationId;
}
#OneToOne
#PrimaryKeyJoinColumn
public User getUser() {
return user;
}
}
Hibernate will make sure that the ID of Validation will be the same as the ID of the User entity set.
Are you using JPA or JPA 2.0 ?
If Validation PK is a FK to User, then you do not need the Long userId attribute in validation class, but instead do the #Id annotation alone. It would be:
Public class Validation
{
#Id
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn(name = "userid", referencedColumnName = "userid")
protected User user;
#Column(name = "code", length = 10, unique = true, nullable = false)
protected String code;
...
public void setUser(User user)
{
this.user = user;
this.userId = user.getUserId();
}
...
}
Try with it and tell us your results.
You need to set both userId and user.
If you set just the user, then the id for Validation is 0 and is deemed detached. If you set just the userId, then you need to make the user property nullable, which doesn't make sense here.
To be safe, you can probably set them both in one method call:
#Transient
public void setUserAndId(User user){
this.userId = user.getId();
this.user = user;
}
I marked the method #Transient so that Hibernate will ignore it. Also, so you can still have setUser and setUserId work as expected with out any "side effects."

Categories

Resources