当前位置: 首页 > 知识库问答 >
问题:

如何使字段在JPA实体中成为可选字段?

卫振
2023-03-14

我在SQL服务器数据库中有表用户,有近30列。我还为相应的数据库表创建了一个JPA实体。JPA实体如下所示:

@Entity
@Table(name="USER")
@Setter
@Getter
public class User{

@Id
@Column(name="ID",nullable=false)
private Integer id;

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

@Column(name="ADDRESS")
private String address;

@Column(name="FATHER_NAME")
private String fathersName;

}

现在我正在尝试创建一个本机查询,它只会从用户表中获取id和name。Repository类看起来像这样。

@Repository
public interface UserDao extends JpaRepository<User,Integer>{

@Query(value=" SELECT u.ID,u.NAME from USER u", nativeQuery=true)
List<User> fetchUser();

}

现在,当它被执行时,它会抛出一个异常,如下所示:

com.microsoft.sqlserver.jdbc.SqlServerException: The column name address is not valid

当我将地址列添加到我的查询时,这个异常会消失,但它会出现在另一个字段中。

com.microsoft.sqlserver.jdbc.SqlServerException: The column name father_name is not valid

所以,现在我想修改JPA实体,使这个字段成为可选的。我试过使用@Transient,但如果其他查询使用这个地址字段,那么在那里它将为null。我还尝试了以下所有注释:

  • @基本
  • @NotFoundAction(action=NotFoundAction. IGNORE)
  • @列(null able="true")
  • @Json物业

但这些注释对我都不起作用。

共有3个答案

商燕七
2023-03-14

自从Java 8发布以来,我经常遇到这个问题。不幸的是,Hibernate和JPA 2.2不支持将Optional作为属性类型。

但是,通过一些技巧,您仍然可以使用Optional作为getter方法的返回类型。如果用@Id注释主键属性,则告诉Hibernate使用字段访问来设置和检索实体属性值。这意味着Hibernate不调用getter或setter方法,您可以以任何方式实现它们。因此,您可以将可选属性包装到可选属性中,而不是直接返回它。

但请注意,这不包括任何延迟加载,只是将数据库列的已选值包装到可选项中。Hibernate需要字节码增强才能启用基本属性的延迟加载。这远远超出了本文的范围,但我在Hibernate性能调整在线培训中详细解释了它。

好的,让我们看一个简单的例子。一本书可能已经出版了,或者作者仍在努力,不久将宣布出版日期。因此,Book实体的publishingDate属性可以为null。以下代码段显示了Book实体的定义。

@Entity
public class Book {
     
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;
 
    @Column(nullable = true)
    private LocalDate publishingDate;
     
    ...
     
    public Optional getPublishingDate() {
        return Optional.ofNullable(publishingDate);
    }
 
    public void setPublishingDate(LocalDate publishingDate) {
        this.publishingDate = publishingDate;
    }
}
胥承
2023-03-14

您可以使用

@Query(value=" SELECT u.ID,u.NAME, '' as address, '' as father_name from USER u", nativeQuery=true)
List<User> fetchUser();

它将这些字段设置为空字符串

申高卓
2023-03-14

您可以为用户实体定义其他构造函数:

@Entity
@Table(name="USER")
public class User {

   public User(){
   }

   public User(Integer id, String name){
      this.id = id;
      this.name = name;
   }

   // ...
}

然后编写以下查询:

@Query("select new your.package.User(u.id, u.name) from User u")
List<User> fetchUser();

请注意,这不是原生的,而是jpql查询。

另请注意,根据hibernate文档:

投影类必须在实体查询中完全限定,并且必须定义匹配的构造函数。这里的类不需要映射。它可以是DTO类。如果它确实代表一个实体,则结果实例将以新状态返回(非托管!)。

编辑

您还可以尝试按以下方式使用spring数据jpa投影:

  1. 定义接口:
interface UserIdWithName {

  Integer getId();
  String getName();
}

这里重要的是,这里定义的属性与聚合实体中的属性完全匹配。

@Query("select u from User u")
List<UserIdWithName> fetchUserIdWithName();

查询执行引擎在运行时为返回的每个元素创建该接口的代理实例,并将对公开方法的调用转发给目标对象。请注意,您不能在此处仅选择查询中的某些字段。

 类似资料:
  • 我有一节这样的课 我希望属性是可选的。如何在Java中实现这一点? 在某些语言中,它非常优雅和简单,我们只需在字段名后附加一个问号。

  • 问题内容: 我有两个JPA实体:和。延伸。两者之间存在ManyToMany关系,并被描述为 “一个VirtualLot可以包含VirtualFiles” 和 “一个VirtualFile可以与多个VirtualLots关联” 。实体定义如下: 在这里,我要总结使用弹簧数据JPA库包含在一个给定的VirtualLot的VirtualFiles的大小:。该查询定义如下: 我的问题是Hibernate

  • 问题内容: 我问这个问题有点傻,但是我找不到这个问题的简单答案。 以这个简单的实体为例: 它代表一个人,因此我想添加一个“ 性别 ”属性。 这将是“男性”或“女性”。所以呢? 我可以使用String,并要记住,“ m”代表男性,“ f”代表女性。 或者,我可以使用布尔值“ isMale”(是或否)。 但是,我认为无论哪种情况,Hibernate纯粹主义者都不会高兴:) 仔细搜索一下,我发现最佳实践

  • 问题内容: 有没有一种方法可以使字段在使用JPA-Hibernate 4进行更新操作时不持久,但在创建操作时持久化? 我以这种方式尝试过 但是使用@Transient注释时,该字段将在所有CRUD操作中都是瞬态的,我想要一种方法来指定仅在此操作上是持久性的(创建)。 有没有办法做到这一点? 谢谢! 问题答案: 如本文所述,您需要设置为: 该属性指示Hibernate从生成的SQL语句中忽略此列。

  • 我试图找到一种方法,在JPQL查询中放置一个计算字段,以映射到Spring Boot中的实体。 我刚才的例子列出了一个静态数字,但我打算将来也将其用于聚合。 我在尝试运行查询时不断收到以下消息: “类[Ljava.lang.Object;不能强制转换为类com.School([Ljava.lang.Object;位于加载器“bootstrap”的模块java.base中;com.School位于加

  • 我有一个实体,它有一个Map ElementCollection字段。我知道使用Jpa,您可以在类级别上使用@Index注释为常规字段定义索引。问题是我的地图元素集合字段创建了一个不是由@Entity注释类创建的连接表。所以我不能使用@Index注释。有没有Jpa/Hibernate方法来定义这个连接表中字段的索引,或者我必须手动定义它们?这是地图字段。 谢谢