简体   繁体   中英

JPA Entity with two fields of the same type

I'm trying to have 2 fields of the same domain class in my entity and I'm getting this error:

org.hibernate.MappingException: Could not determine type for: com.packt.webapp.domain.User, at table: opinions, for columns: [org.hibernate.mapping.Column(author)]

My entities:

@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;

I just want to map opinions to commented users and storage author of comment in author field. When I remove author field, everything works. Whats wrong with this example?

Try annotating also author?

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

It's complaining that it doesn't know how to map the author field. You can provide a mapping similar to how you mapped writtenTo . An opinion has one author and an author can have authored many opinions.

If you would like to ignore a field for mapping, annotate it with @Transient . The transient annotation prevents that field from being persisted to the database otherwise you have to map it like so:

Opinion entity:

@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
}

User entity:

@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
}

Just apply the @ManyToOne annotation at both the User fields.

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

But there is a more flexible solution to problems like this. Replace the @OneToMany and @ManyToOne relations by @ManyToMany ones. Create a User and a Role entity (with descendats for the ones with specific fields). A User could have many roles (writer, author, etc) and a Role could be played by many users. In this case you can change your mind and create/remove/attach/detach roles dynamically without any data structure changing on the existing tables.

@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;
}

And you can get/check the user roles by role ids/names using a utility class:

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;
  }
}

The client code to checking a role:

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

Stay at you example with this solution you can add a censor/moderator to the opinion or something like that without any data structure changing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM