【问题标题】:JPA Entity with two fields of the same type具有两个相同类型字段的 JPA 实体
【发布时间】:2017-08-20 18:18:49
【问题描述】:

我试图在我的实体中拥有相同域类的 2 个字段,但出现此错误:

org.hibernate.MappingException:无法确定类型:com.packt.webapp.domain.User,在表:意见,列:[org.hibernate.mapping.Column(作者)]

我的实体:

@Entity
@Table(name="opinions")
public class Opinion {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @NotNull
    private String text;
    @NotNull
    private String date;
    @ManyToOne
    @JoinColumn(name="commented_user")
    private User writtenTo;
    private User author;

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

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String username;
    private String password;
    @OneToMany(mappedBy="writtenTo")
    private List<Opinion> opinions;

我只想将意见映射到author 字段中的评论用户和评论的存储作者。当我删除 author 字段时,一切正常。这个例子有什么问题?

【问题讨论】:

  • 为什么不从 User 中删除 List&lt;Opinion&gt; opinions 并使用 JPQL 进行查询?
  • 您是否尝试对writtenTo 和author 都使用ManyToOne 注释?
  • @michaeak 你的意思是有 2 个简单的字段,例如:commentedUserauthor?这是个好主意 :) 但我只是想知道为什么我的代码不起作用。
  • @jmw5598 不,我尝试仅在 writtenTo 上使用它。
  • 它正在尝试映射作者,但由于您没有提供关系,所以不知道如何。您可以使用与映射writtenTo 类似的方式对其进行映射

标签: java spring hibernate jpa


【解决方案1】:

它抱怨它不知道如何映射author 字段。您可以提供类似于映射writtenTo 的映射。一个意见有一个作者,一个作者可以发表多个意见。

如果您想忽略映射字段,请使用@Transient 对其进行注释。瞬态注释可防止该字段被持久化到数据库中,否则您必须像这样映射它:

意见实体:

@Entity
@Table(name="opinions")
public class Opinion {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @NotNull
    private String text;

    @NotNull
    private String date;

    @ManyToOne
    @JoinColumn(name="commented_user")
    private User writtenTo;

    // map author to User entity
    @ManyToOne
    @JoinColumn(name="authored_user")
    private User author;

    // getters and setters
}

用户实体:

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

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String username;

    private String password;

    @OneToMany(mappedBy="writtenTo")
    private List<Opinion> opinions;

    // map opinions to the author
    @OneToMany(mappedBy="author")
    private List<Opinion> authoredOpinions;

    // getters and setters
}

【讨论】:

  • 请注意,@JoinColumn 通常是不必要的,除非覆盖到预先存在的 SQL 架构上。
【解决方案2】:

尝试同时注释作者?

@ManyToOne
@JoinColumn(name="author")
private User author;

【讨论】:

    【解决方案3】:

    只需在两个用户字段中应用@ManyToOne 注释。

    @ManyToOne
    @JoinColumn(name="commented_user")
    private User writtenTo;
    @ManyToOne
    @JoinColumn(name="author")
    private User author;
    

    但是对于此类问题,有更灵活的解决方案。用@ManyToMany 替换@OneToMany 和@ManyToOne 关系。创建一个用户和一个角色实体(具有特定字段的实体的后代)。一个用户可以有多个角色(作者、作者等),一个角色可以由多个用户扮演。在这种情况下,您可以改变主意并动态创建/删除/附加/分离角色,而无需更改现有表的任何数据结构。

    @Entity
    public class User
    {
      @Id
      private Long id;
      @Column
      private String name;
      @ManyToMany
      @JoinTable(
          name="User_Role",
          joinColumns=@JoinColumn(name="UserID", referencedColumnName="ID"),
          inverseJoinColumns=@JoinColumn(name="RoleID", referencedColumnName="ID"))
      private List<Role> roles;
    }
    
    @Entity
    public class Role
    {
      @Id
      private Long id;
      @Column
      private String name;
      @ManyToMany( mappedBy="roles" )
      private List<User> users;
    }
    

    您可以使用实用程序类通过角色 ID/名称获取/检查用户角色:

    puclic class RoleUtility
    {
      public Role getUserRoleByName( User user_, String roleName_ )
      {
        User retRole = null;
        Iterator<Role> i = roles_.iterator();
        while ( ( retRole == null ) && i.hasNext() )
        {
          Role role = (Role) i.next();
          if ( roleName_.isEqual( role.getName ) )
            retRole = role;
        }
        return retRole;
      }
    }
    

    检查角色的客户端代码:

    User user = ...
    Role role = RoleUtility.getRoleByName( user.getRoles(), roleName );
    

    使用此解决方案作为示例,您可以在意见或类似内容中添加审查员/主持人,而无需更改任何数据结构。

    【讨论】:

      猜你喜欢
      • 2013-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-24
      • 1970-01-01
      • 2013-11-24
      • 2019-08-19
      • 2016-05-02
      相关资源
      最近更新 更多