Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在JPA中使用可嵌入Id持久化OneToMany_Java_Database_Spring_Hibernate_Jpa - Fatal编程技术网

Java 在JPA中使用可嵌入Id持久化OneToMany

Java 在JPA中使用可嵌入Id持久化OneToMany,java,database,spring,hibernate,jpa,Java,Database,Spring,Hibernate,Jpa,授权服务基于(遗憾的是,它没有提供注册示例) 我拥有以下实体和服务: User.java package com.test.entity; import javax.persistence.*; import java.io.Serializable; import java.sql.Timestamp; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @Entity @Ta

授权服务基于(遗憾的是,它没有提供注册示例)

我拥有以下实体和服务:

User.java

package com.test.entity;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "user")
public class User implements Serializable {
  private static final long serialVersionUID = 1322120000551624359L;

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column(name = "username")
  private String username;

  @Column(name = "password")
  private String password;

  @Column(name = "first_name")
  private String firstName;

  @Column(name = "last_name")
  private String lastName;

  @Column(name = "activated")
  private Boolean activated;

  @Column(name = "activation_token")
  private String activationToken;

  @Column(name = "activation_token_exp")
  private Timestamp activationTokenExpirationDate;

  @Column(name = "reset_token")
  private String resetToken;

  @Column(name = "reset_token_exp")
  private Timestamp resetTokenExpirationDate;

  @Column(name = "created")
  private LocalDateTime created;

  @Column(name = "updated")
  private LocalDateTime updated;

  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = "user_id", referencedColumnName = "id")
  private List<UserRole> roles = new ArrayList<>(0);

  public User() { }

  // getters and setters
}
@Entity
@Table(name = "user_role")
public class UserRole implements Serializable {
  @Embeddable
  public static class Id implements Serializable {
    private static final long serialVersionUID = 1322120000551624359L;

    @Column(name = "user_id")
    protected Long userId;

    @Enumerated(EnumType.STRING)
    @Column(name = "role")
    protected Role role;

    public Id() { }

    public Id(Long userId, Role role) {
      this.userId = userId;
      this.role = role;
    }

    @Override
    public boolean equals(Object o) {
      if (this == o)
        return true;
      if (o == null || getClass() != o.getClass())
        return false;

      Id id = (Id) o;

      if (! userId.equals(id.userId))
        return false;
      return role == id.role;
    }

    @Override
    public int hashCode() {
      int result = userId.hashCode();
      result = 31 * result + role.hashCode();
      return result;
    }
  }

  @EmbeddedId
  Id id = new Id();

  @Enumerated(EnumType.STRING)
  @Column(name = "role", insertable = false, updatable = false)
  protected Role role;

  public UserRole() {
  }

  public UserRole(Role role) {
    this.role = role;
  }

  public Role getRole() {
    return role;
  }

  public void setRole(Role role) {
    this.role = role;
  }
}
@Override
  public User registerUser(UserDTO userDto) {
    Optional<User> existingUser = this.getByUsername(userDto.getUsername());
    if (existingUser.isPresent()) {
      throw new RegistrationException("User is already taken");
    }

    User newUser = new User();
    newUser.setUsername(userDto.getUsername());
    newUser.setPassword(encoder.encode(userDto.getPassword()));
    newUser.setFirstName(userDto.getFirstName());
    newUser.setLastName(userDto.getLastName());
    newUser.setActivated(Boolean.FALSE);
    newUser.setActivationToken(RandomUtil.generateActivationKey());
    newUser.setActivationTokenExpirationDate(Timestamp.valueOf(LocalDateTime.now().plusSeconds(ACTIVATION_TOKEN_TTL)));
    newUser.setCreated(LocalDateTime.now());

    newUser.addRole(new UserRole(Role.MEMBER));

    return userRepository.save(newUser);
  }
UserService.java

package com.test.entity;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "user")
public class User implements Serializable {
  private static final long serialVersionUID = 1322120000551624359L;

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column(name = "username")
  private String username;

  @Column(name = "password")
  private String password;

  @Column(name = "first_name")
  private String firstName;

  @Column(name = "last_name")
  private String lastName;

  @Column(name = "activated")
  private Boolean activated;

  @Column(name = "activation_token")
  private String activationToken;

  @Column(name = "activation_token_exp")
  private Timestamp activationTokenExpirationDate;

  @Column(name = "reset_token")
  private String resetToken;

  @Column(name = "reset_token_exp")
  private Timestamp resetTokenExpirationDate;

  @Column(name = "created")
  private LocalDateTime created;

  @Column(name = "updated")
  private LocalDateTime updated;

  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = "user_id", referencedColumnName = "id")
  private List<UserRole> roles = new ArrayList<>(0);

  public User() { }

  // getters and setters
}
@Entity
@Table(name = "user_role")
public class UserRole implements Serializable {
  @Embeddable
  public static class Id implements Serializable {
    private static final long serialVersionUID = 1322120000551624359L;

    @Column(name = "user_id")
    protected Long userId;

    @Enumerated(EnumType.STRING)
    @Column(name = "role")
    protected Role role;

    public Id() { }

    public Id(Long userId, Role role) {
      this.userId = userId;
      this.role = role;
    }

    @Override
    public boolean equals(Object o) {
      if (this == o)
        return true;
      if (o == null || getClass() != o.getClass())
        return false;

      Id id = (Id) o;

      if (! userId.equals(id.userId))
        return false;
      return role == id.role;
    }

    @Override
    public int hashCode() {
      int result = userId.hashCode();
      result = 31 * result + role.hashCode();
      return result;
    }
  }

  @EmbeddedId
  Id id = new Id();

  @Enumerated(EnumType.STRING)
  @Column(name = "role", insertable = false, updatable = false)
  protected Role role;

  public UserRole() {
  }

  public UserRole(Role role) {
    this.role = role;
  }

  public Role getRole() {
    return role;
  }

  public void setRole(Role role) {
    this.role = role;
  }
}
@Override
  public User registerUser(UserDTO userDto) {
    Optional<User> existingUser = this.getByUsername(userDto.getUsername());
    if (existingUser.isPresent()) {
      throw new RegistrationException("User is already taken");
    }

    User newUser = new User();
    newUser.setUsername(userDto.getUsername());
    newUser.setPassword(encoder.encode(userDto.getPassword()));
    newUser.setFirstName(userDto.getFirstName());
    newUser.setLastName(userDto.getLastName());
    newUser.setActivated(Boolean.FALSE);
    newUser.setActivationToken(RandomUtil.generateActivationKey());
    newUser.setActivationTokenExpirationDate(Timestamp.valueOf(LocalDateTime.now().plusSeconds(ACTIVATION_TOKEN_TTL)));
    newUser.setCreated(LocalDateTime.now());

    newUser.addRole(new UserRole(Role.MEMBER));

    return userRepository.save(newUser);
  }
这是在将复合主键作为可嵌入主键的同时保持这种关系的正确方法吗

如果我避免使用UserRole设置realation,那么用户将正确持久化(没有角色)

DB

CREATE TABLE `user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(64) NOT NULL,
  `first_name` varchar(20) DEFAULT NULL,
  `last_name` varchar(20) DEFAULT NULL,
  `activated` tinyint(1) NOT NULL DEFAULT '0',
  `activation_token` varchar(50) DEFAULT NULL,
  `activation_token_exp` timestamp NULL DEFAULT NULL,
  `reset_token` varchar(50) DEFAULT NULL,
  `reset_token_exp` timestamp NULL DEFAULT NULL,
  `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;

CREATE TABLE `user_role` (
  `user_id` bigint(20) unsigned NOT NULL,
  `role` varchar(50) NOT NULL DEFAULT '',
  PRIMARY KEY (`user_id`,`role`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

UserRole
中,角色映射两次:一次作为简单属性

@Enumerated(EnumType.STRING)
@Column(name = "role", insertable = false, updatable = false)
protected Role role;
再一次在嵌入的id中:

@Enumerated(EnumType.STRING)
@Column(name = "role")
protected Role role;
在调用
userRepository.save(newUser)
时,您仅将简单属性
UserRole.role
设置为指向非空角色。但是,由于简单属性被标记为
insertable=false
,因此在
INSERT
语句中会忽略它
UserRole.id.role
依次设置为
null
,这是
INSERT
语句考虑的值。由于您已经为
角色
列创建了非空约束,
插入
语句失败

(请注意,
DEFAULT'
仅在
INSERT
子句的字段列表中不存在该列时才使用,此处不是这种情况)


简单地说,解决方案是在设置
User.role
时更新
UserRole.id.role
的值

UserRole
中,角色映射两次:一次作为简单属性

@Enumerated(EnumType.STRING)
@Column(name = "role", insertable = false, updatable = false)
protected Role role;
再一次在嵌入的id中:

@Enumerated(EnumType.STRING)
@Column(name = "role")
protected Role role;
在调用
userRepository.save(newUser)
时,您仅将简单属性
UserRole.role
设置为指向非空角色。但是,由于简单属性被标记为
insertable=false
,因此在
INSERT
语句中会忽略它
UserRole.id.role
依次设置为
null
,这是
INSERT
语句考虑的值。由于您已经为
角色
列创建了非空约束,
插入
语句失败

(请注意,
DEFAULT'
仅在
INSERT
子句的字段列表中不存在该列时才使用,此处不是这种情况)


简单地说,解决方案是在设置
User.role
时更新
UserRole.id.role
的值

您的
UserRole
类映射不正确。您已经映射了两次
Role
,一次通过
EmbeddedId
映射,一次直接映射到
UserRole
。您必须删除第二个
UserRole
,该类将如下所示

@Entity
@Table(name = "user_role")
public class UserRole implements Serializable {
    @Embeddable
    public static class Id implements Serializable {
        private static final long serialVersionUID = 1322120000551624359L;

        @Column(name = "user_id")
        protected Long userId;

        @Enumerated(EnumType.STRING)
        @Column(name = "role")
        protected Role role;

        public Id() {
        }

        public Id(Long userId, Role role) {
            this.userId = userId;
            this.role = role;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            Id id = (Id) o;

            if (!userId.equals(id.userId))
                return false;
            return role == id.role;
        }

        @Override
        public int hashCode() {
            int result = userId.hashCode();
            result = 31 * result + role.hashCode();
            return result;
        }
    }

    @EmbeddedId
    Id id;

    public UserRole(Id id) {
        super();
        this.id = id;
    }

    public Id getId() {
        return id;
    }

    public void setId(Id id) {
        this.id = id;
    }
}
另外,请注意,
Id
不再初始化。请将注册表服务器更改为:

public User registerUser(String userName) {

    User newUser = new User();
    newUser.setUsername(userName);
    newUser.setPassword("password");
    newUser.setFirstName("name");
    //set other fields.

    userRepository.save(newUser);
    newUser.addRole(new UserRole(new UserRole.Id(newUser.getId(), Role.MEMBER)))
    userRepository.save(newUser);

    return newUser; 
}

当您为
user\u role
创建复合主键时,您只提供role而不提供user\u id,JPA会将user\u id抱怨为null。我们需要两者兼备

您的
UserRole
类映射不正确。您已经映射了两次
Role
,一次通过
EmbeddedId
映射,一次直接映射到
UserRole
。您必须删除第二个
UserRole
,该类将如下所示

@Entity
@Table(name = "user_role")
public class UserRole implements Serializable {
    @Embeddable
    public static class Id implements Serializable {
        private static final long serialVersionUID = 1322120000551624359L;

        @Column(name = "user_id")
        protected Long userId;

        @Enumerated(EnumType.STRING)
        @Column(name = "role")
        protected Role role;

        public Id() {
        }

        public Id(Long userId, Role role) {
            this.userId = userId;
            this.role = role;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            Id id = (Id) o;

            if (!userId.equals(id.userId))
                return false;
            return role == id.role;
        }

        @Override
        public int hashCode() {
            int result = userId.hashCode();
            result = 31 * result + role.hashCode();
            return result;
        }
    }

    @EmbeddedId
    Id id;

    public UserRole(Id id) {
        super();
        this.id = id;
    }

    public Id getId() {
        return id;
    }

    public void setId(Id id) {
        this.id = id;
    }
}
另外,请注意,
Id
不再初始化。请将注册表服务器更改为:

public User registerUser(String userName) {

    User newUser = new User();
    newUser.setUsername(userName);
    newUser.setPassword("password");
    newUser.setFirstName("name");
    //set other fields.

    userRepository.save(newUser);
    newUser.addRole(new UserRole(new UserRole.Id(newUser.getId(), Role.MEMBER)))
    userRepository.save(newUser);

    return newUser; 
}
当您为
user\u role
创建复合主键时,您只提供role而不提供user\u id,JPA会将user\u id抱怨为null。我们需要两者兼备