Hibernate抛出org.hibernate.AnnotationException异常:实体com..domain.idea.MAE_MFEView未指定标识符。

272

为什么我会收到这个异常?

package com.domain.idea;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.AccessType;

/**
 * object model for the view [InvestmentReturn].[vMAE_MFE]
 */
@Entity
@Table(name="vMAE_MFE", schema="InvestmentReturn")
@AccessType("field")
public class MAE_MFEView
{
    /**
     * trade property is a SuggestdTradeRecommendation object
     */
    @OneToOne(fetch = FetchType.LAZY , cascade = { CascadeType.PERSIST })
    @JoinColumn(name = "suggestedTradeRecommendationID")
    private SuggestedTradeRecommendation trade;

    /**
     * Most Adeverse Excursion value
     */
    private int MAE;

    public int getMAE()
    {
        return MAE;
    }

    /**
     * Most Favorable Excursion value
     */
    private int MFE;

    public int getMFE()
    {
        return MFE;
    }

    /**
     * @return trade property
     * see #trade
     */
    public SuggestedTradeRecommendation getTrade()
    {
        return trade;
    }
}

更新:我已经将我的代码更改为以下形式:

package com.domain.idea;

import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.AccessType;

/**
 * object model for the view [InvestmentReturn].[vMAE_MFE]
 */
@Entity
@Table(name="vMAE_MFE", schema="InvestmentReturn")
@AccessType("field")
public class MAE_MFEView
{
    /**
     * trade property is a SuggestdTradeRecommendation object
     */
    @Id
    @OneToOne(fetch = FetchType.LAZY , cascade = { CascadeType.PERSIST })
    @JoinColumn(name = "suggestedTradeRecommendationID")
    private SuggestedTradeRecommendation trade;

    /**
     * Most Adeverse Excursion value
     */
    private int MAE;

    public int getMAE()
    {
        return MAE;
    }

    /**
     * Most Favorable Excursion value
     */
    private int MFE;

    public int getMFE()
    {
        return MFE;
    }

    /**
     * @return trade property
     * see #trade
     */
    public SuggestedTradeRecommendation getTrade()
    {
        return trade;
    }
}

但现在我收到了这个异常:

Caused by: org.hibernate.MappingException: Could not determine type for: com.domain.idea.SuggestedTradeRecommendation, at table: vMAE_MFE, for columns: [org.hibernate.mapping.Column(trade)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:292)
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:276)
    at org.hibernate.mapping.RootClass.validate(RootClass.java:216)
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1135)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1320)
    at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:669)
    ... 145 more

顺便说一句,与问题无关,那是一个相当长的堆栈跟踪。您有一些重复的调用。您确定那里的一切都正确吗? - Bozho
不太确定为什么堆栈跟踪总是这么长。我认为有很多后台服务正在运行受到影响。 - Ramy
请注意,如果您的ID不是静态的或者类上有一些属性。这种情况曾经发生在我身上 :) - Gean Felipe
15个回答

538

您缺少一个带有@Id标注的字段。每个@Entity都需要一个@Id - 这是数据库中的主键。

如果您不想让实体在单独的表中持久化,而是要成为其他实体的一部分,则可以使用@Embeddable而不是@Entity

如果您只想要一个数据传输对象来保存一些来自Hibernate实体的数据,请不要在其上使用任何注释 - 将其保留为简单的pojo。

更新:关于SQL视图,Hibernate文档写道:

对于Hibernate映射,视图和基本表之间没有区别。这在数据库层面上是透明的。


3
我需要有一个@Id字段吗?严格来说,我的视图没有ID。 - Ramy
1
好的,给视图分配一些ID。没有它不行。每一行(对象)都必须有唯一的标识。 - Bozho
3
谢谢!这解决了一个非常烦人的NullPointerFromHellException错误! - malix
2
换句话说,Hibernate 不支持没有主键的表吗? - AlikElzin-kilaka
3
我可以代表一个没有主键的表格。这不可能吗? - Yeung
显示剩余8条评论

291

对于我来说,应该使用javax.persistence.Id而不是org.springframework.data.annotation.Id。对于遇到这个问题的任何人,您可以检查是否导入了正确的Id类。

如果您使用IntelliJ(以及其他一些IDE)的自动建议功能而没有仔细查看导入内容,则通常会发生此情况。


是的,IntelliJ自动完成出了问题!非常感谢您提供的答案。 - sunitkatkar

76

当您为@Id导入不同的库时,可能会引发此错误; 您也需要注意这种情况。

在我的情况下,我有

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Table;

import org.springframework.data.annotation.Id;

@Entity
public class Status {

    @Id
    @GeneratedValue
    private int id;

当我将代码改成这样时,它就能工作了

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Table;

import javax.persistence.Id;

@Entity
public class Status {

    @Id
    @GeneratedValue
    private int id;

5
宝贵建议:请不要使用org.springframework.data.annotation.Id。 - Christian Meyer
1
非常感谢……我知道很多人会注意到这些小细节,并追求不太明显的答案。但是真的非常感谢你为此付出了如此多的努力。我在这个问题上花了大约30分钟,学到了一个宝贵的教训,就是要慢慢来哈哈。 - William Tolliver

14

下面的代码可以解决空指针异常。

@Id
@GeneratedValue
@Column(name = "STOCK_ID", unique = true, nullable = false)
public Integer getStockId() {
    return this.stockId;
}
public void setStockId(Integer stockId) {
    this.stockId = stockId;
}

如果您添加@Id,那么您可以声明一些类似于上面声明的方法。


因为您的@Id值没有被分配和更新到任何地方,所以您得到了空指针异常... - Shivendra Prakash Shukla

11

简述

你缺少实体属性@Id,这就是Hibernate抛出异常的原因。

实体标识符

任何JPA实体都必须具有标识属性,并带有Id注释。

有两种类型的标识符:

  • 分配
  • 自动生成

分配的标识符

分配的标识符如下所示:

@Id
private Long id;

请注意,我们使用的是包装器(例如LongInteger),而不是基本类型(例如longint)。 在使用Hibernate时,使用包装类型是更好的选择,因为通过检查id是否为null,Hibernate可以更好地确定实体是瞬态的(它没有关联的表行)还是分离的(它具有关联的表行,但它不是由当前持久性上下文管理的)。
应用程序在调用persist之前必须手动设置指定的标识符:
Post post = new Post();
post.setId(1L);

entityManager.persist(post);

自动生成的标识符

自动生成的标识符需要在@Id注解旁边加上@GeneratedValue注解:

@Id
@GeneratedValue
private int id;

Hibernate可以使用三种策略自动生成实体标识符:
  • IDENTITY
  • SEQUENCE
  • TABLE
如果底层数据库支持序列(例如Oracle、PostgreSQL、MariaDB since 10.3、2012年以后的SQL Server),则应避免使用IDENTITY策略。唯一不支持序列的主要数据库是MySQL。
IDENTITY的问题在于此策略禁用了自动的Hibernate批量插入

SEQUENCE策略是最好的选择,除非你使用MySQL。对于SEQUENCE策略,您还需要使用pooled优化器来减少在同一持久性上下文中持久化多个实体时的数据库往返次数。

TABLE生成器是一个糟糕的选择,因为它不具备可扩展性。为了实现可移植性,最好默认使用SEQUENCE,并仅在MySQL中切换到IDENTITY


第一个例子不应该有@GeneratedValue,对吧? - Josef Cech

6
我认为这个问题是由于错误的导入模型类造成的。
    import org.springframework.data.annotation.Id;

通常情况下,它应该是这样的:
    import javax.persistence.Id;

4

使用@EmbeddableId作为主键实体解决了我的问题。

@Entity
@Table(name="SAMPLE")
 public class SampleEntity implements Serializable{
   private static final long serialVersionUID = 1L;

   @EmbeddedId
   SampleEntityPK id;

 }

1
您的回复涉及到两个注释,其中一个似乎不存在(@EmbeddableId)。 - Jaroslav Záruba

3
  1. 因导入错误的包而出现此错误:
    import javax.persistence.Id;
  2. 你应该始终为表提供主键,否则将会出现错误。

2

这个错误是由于导入了错误的Id类而引起的。将org.springframework.data.annotation.Id更改为javax.persistence.Id后,应用程序就可以运行了。


2
我知道听起来很疯狂,但我收到了这样的错误,因为我忘记删除某些内容。
private static final long serialVersionUID = 1L;

我曾经对表格进行了实体转换,Eclipse JPA工具自动生成了上述代码。

删除上面的代码即可解决问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接