为什么这个 Spring Data JPA query by name 方法给我这个错误,而 Eclipse 强制我 return 一个 Optional<User> 而不是一个简单的 User 对象?
Why this Spring Data JPA query by name method gives me this error and Eclipse forces me to return an Optional<User> instead a simple User object?
我正在使用 Spring Data JPA 和 Hibernate 映射开发 Spring 引导项目。在我的存储库 classes 中,我正在使用 通过方法名称查询 并且我有以下问题。我有这个 User 实体 class:
@Entity
@Table(name = "portal_user")
@Getter
@Setter
public class User implements Serializable {
private static final long serialVersionUID = 5062673109048808267L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@Column(name = "first_name")
@NotNull(message = "{NotNull.User.firstName.Validation}")
private String firstName;
@Column(name = "middle_name")
private String middleName;
@Column(name = "surname")
@NotNull(message = "{NotNull.User.surname.Validation}")
private String surname;
@Column(name = "sex")
@NotNull(message = "{NotNull.User.sex.Validation}")
private char sex;
@Column(name = "birthdate")
@NotNull(message = "{NotNull.User.birthdate.Validation}")
private Date birthdate;
@Column(name = "tax_code")
@NotNull(message = "{NotNull.User.taxCode.Validation}")
private String taxCode;
@Column(name = "e_mail")
@NotNull(message = "{NotNull.User.email.Validation}")
private String email;
@Column(name = "pswd")
@NotNull(message = "{NotNull.User.pswd.Validation}")
private String pswd;
@Column(name = "contact_number")
@NotNull(message = "{NotNull.User.contactNumber.Validation}")
private String contactNumber;
@Temporal(TemporalType.DATE)
@Column(name = "created_at")
private Date createdAt;
@Column(name = "is_active")
private boolean is_active;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
@ManyToMany(cascade = { CascadeType.MERGE })
@JoinTable(
name = "portal_user_user_type",
joinColumns = { @JoinColumn(name = "portal_user_id_fk") },
inverseJoinColumns = { @JoinColumn(name = "user_type_id_fk") }
)
Set<UserType> userTypes;
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
String email, String pswd, String contactNumber, Date createdAt, boolean is_active) {
super();
this.firstName = firstName;
this.middleName = middleName;
this.surname = surname;
this.sex = sex;
this.birthdate = birthdate;
this.taxCode = taxCode;
this.email = email;
this.pswd = pswd;
this.contactNumber = contactNumber;
this.createdAt = createdAt;
this.is_active = is_active;
}
}
然后我有这个存储库界面:
public interface UsersRepository extends JpaRepository<User, Integer> {
/**
* Retrieve an user by its e-mail address:
* @param email is the e-mail of the user
* @return the user related to the specified e-mail
*/
User findByemail(String email);
/**
* Retrieve the list of users belonging to a specific user type
* @param typeName is the name of the user type
* @return the list of users belonging to a specific user type
*/
List<User> findByUserTypes_TypeName(String typeName);
/**
* Retrieve the list of users children of an user.
* Generally used to retrieve the client users of a specific sub-agent user
* @param id is the id of the parent user
* @return the list of children of a specific user (generally used to retrieve the client users of a specific sub-agent user)
*/
List<User> findByParent_Id(Integer id);
/**
* Retrieve an user starting from is id
* @param id of the user which you want to retrieve
* @return the retrieved object
*/
Optional<User> findById(Integer id);
}
我怀疑最后一个方法(旨在通过其自己的 id 字段值检索 User 对象,这个:
Optional<User> findById(Integer id);
最初我试图将其简单定义为:
User findById(Integer id);
但是这样做 Eclipse\STS 给我以下错误:
Multiple markers at this line
- implements org.springframework.data.repository.CrudRepository<com.easydefi.users.entity.User,java.lang.Integer>.
findById
- The return type is incompatible with CrudRepository<User,Integer>.findById(Integer)
- The return type is incompatible with CrudRepository<User,Integer>.findById(Integer)
为什么会出现这个错误?以及为什么 Eclipse 强制我将 return Optional<User>
作为 returned 类型?这是什么可选?为什么在 findByemail() 中允许我 return 一个简单的 User 类型?
正如您在 JpaRepository
扩展的 CrudRepository
接口的 JavaDoc 中看到的那样,已经有一个具有相同签名的 findById
方法。
Java 重写规则不允许您使用具有相同名称和参数的方法以及与父 class 定义不一致的 return 类型(在此例,Optional<User>
).
如果您以某种方式更改方法名称,Spring Data JPA 将能够使用普通引用。在这种情况下,如果未找到实体,null
将被 returned。但是,对于您的情况,您应该只删除 findById
方法。
您的存储库扩展了 JpaRepository。 JpaRepository 扩展了 PagingAndSortingRepository,后者扩展了 CrudRepository。 CrudRepository 有方法:Optional<T> findById(ID var1);
。
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html
当您使用此签名定义方法时,您将覆盖 CrudRepository 方法。但是,如果您为存储库中创建的此方法定义不同的 return 类型,您的代码将无法编译。
Optional创建于Java 8、resume中,用于表示method的return数据可能为null。在这些情况下使用 Optional 是一种很好的做法。
https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
关于您提到的其他方法,它们只是您可以根据需要创建的 UsersRepository 的方法。
Alexy 和 Raul 已经很好地解释了为什么这不起作用。
但是为避免该问题提供的选项相当有限。
以下是您拥有的最相关的选项:
省略您的 findById
方法,只使用 CrudRepository
提供的方法。可行,但您似乎不想要 Optional
,所以这并不令人满意。
您可以使用 find
的替代方法来修改方法名称,例如search
或 query
。请参阅 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-keywords 以获取可能使用的单词列表。
您还可以在 find
和 By
之间添加任何内容。 findUserById
也可以。
您可以决定不继承 CrudRepository
。这当然也会删除 CrudRepository
的所有其他方法。但是如果你将它们的声明复制到你的存储库接口中,它们将得到正确的实现。您也可以使用此变体来删除您可能不想在存储库中包含的方法。
我正在使用 Spring Data JPA 和 Hibernate 映射开发 Spring 引导项目。在我的存储库 classes 中,我正在使用 通过方法名称查询 并且我有以下问题。我有这个 User 实体 class:
@Entity
@Table(name = "portal_user")
@Getter
@Setter
public class User implements Serializable {
private static final long serialVersionUID = 5062673109048808267L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@Column(name = "first_name")
@NotNull(message = "{NotNull.User.firstName.Validation}")
private String firstName;
@Column(name = "middle_name")
private String middleName;
@Column(name = "surname")
@NotNull(message = "{NotNull.User.surname.Validation}")
private String surname;
@Column(name = "sex")
@NotNull(message = "{NotNull.User.sex.Validation}")
private char sex;
@Column(name = "birthdate")
@NotNull(message = "{NotNull.User.birthdate.Validation}")
private Date birthdate;
@Column(name = "tax_code")
@NotNull(message = "{NotNull.User.taxCode.Validation}")
private String taxCode;
@Column(name = "e_mail")
@NotNull(message = "{NotNull.User.email.Validation}")
private String email;
@Column(name = "pswd")
@NotNull(message = "{NotNull.User.pswd.Validation}")
private String pswd;
@Column(name = "contact_number")
@NotNull(message = "{NotNull.User.contactNumber.Validation}")
private String contactNumber;
@Temporal(TemporalType.DATE)
@Column(name = "created_at")
private Date createdAt;
@Column(name = "is_active")
private boolean is_active;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
@ManyToMany(cascade = { CascadeType.MERGE })
@JoinTable(
name = "portal_user_user_type",
joinColumns = { @JoinColumn(name = "portal_user_id_fk") },
inverseJoinColumns = { @JoinColumn(name = "user_type_id_fk") }
)
Set<UserType> userTypes;
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
String email, String pswd, String contactNumber, Date createdAt, boolean is_active) {
super();
this.firstName = firstName;
this.middleName = middleName;
this.surname = surname;
this.sex = sex;
this.birthdate = birthdate;
this.taxCode = taxCode;
this.email = email;
this.pswd = pswd;
this.contactNumber = contactNumber;
this.createdAt = createdAt;
this.is_active = is_active;
}
}
然后我有这个存储库界面:
public interface UsersRepository extends JpaRepository<User, Integer> {
/**
* Retrieve an user by its e-mail address:
* @param email is the e-mail of the user
* @return the user related to the specified e-mail
*/
User findByemail(String email);
/**
* Retrieve the list of users belonging to a specific user type
* @param typeName is the name of the user type
* @return the list of users belonging to a specific user type
*/
List<User> findByUserTypes_TypeName(String typeName);
/**
* Retrieve the list of users children of an user.
* Generally used to retrieve the client users of a specific sub-agent user
* @param id is the id of the parent user
* @return the list of children of a specific user (generally used to retrieve the client users of a specific sub-agent user)
*/
List<User> findByParent_Id(Integer id);
/**
* Retrieve an user starting from is id
* @param id of the user which you want to retrieve
* @return the retrieved object
*/
Optional<User> findById(Integer id);
}
我怀疑最后一个方法(旨在通过其自己的 id 字段值检索 User 对象,这个:
Optional<User> findById(Integer id);
最初我试图将其简单定义为:
User findById(Integer id);
但是这样做 Eclipse\STS 给我以下错误:
Multiple markers at this line
- implements org.springframework.data.repository.CrudRepository<com.easydefi.users.entity.User,java.lang.Integer>.
findById
- The return type is incompatible with CrudRepository<User,Integer>.findById(Integer)
- The return type is incompatible with CrudRepository<User,Integer>.findById(Integer)
为什么会出现这个错误?以及为什么 Eclipse 强制我将 return Optional<User>
作为 returned 类型?这是什么可选?为什么在 findByemail() 中允许我 return 一个简单的 User 类型?
正如您在 JpaRepository
扩展的 CrudRepository
接口的 JavaDoc 中看到的那样,已经有一个具有相同签名的 findById
方法。
Java 重写规则不允许您使用具有相同名称和参数的方法以及与父 class 定义不一致的 return 类型(在此例,Optional<User>
).
如果您以某种方式更改方法名称,Spring Data JPA 将能够使用普通引用。在这种情况下,如果未找到实体,null
将被 returned。但是,对于您的情况,您应该只删除 findById
方法。
您的存储库扩展了 JpaRepository。 JpaRepository 扩展了 PagingAndSortingRepository,后者扩展了 CrudRepository。 CrudRepository 有方法:Optional<T> findById(ID var1);
。
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html
当您使用此签名定义方法时,您将覆盖 CrudRepository 方法。但是,如果您为存储库中创建的此方法定义不同的 return 类型,您的代码将无法编译。
Optional创建于Java 8、resume中,用于表示method的return数据可能为null。在这些情况下使用 Optional 是一种很好的做法。 https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
关于您提到的其他方法,它们只是您可以根据需要创建的 UsersRepository 的方法。
Alexy 和 Raul 已经很好地解释了为什么这不起作用。 但是为避免该问题提供的选项相当有限。 以下是您拥有的最相关的选项:
省略您的
findById
方法,只使用CrudRepository
提供的方法。可行,但您似乎不想要Optional
,所以这并不令人满意。您可以使用
find
的替代方法来修改方法名称,例如search
或query
。请参阅 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-keywords 以获取可能使用的单词列表。您还可以在
find
和By
之间添加任何内容。findUserById
也可以。您可以决定不继承
CrudRepository
。这当然也会删除CrudRepository
的所有其他方法。但是如果你将它们的声明复制到你的存储库接口中,它们将得到正确的实现。您也可以使用此变体来删除您可能不想在存储库中包含的方法。