Question

I see many turoials and articles about subject, but i can't understand one thing. For a example: i have "User" table with fields "id", "name" and i have "UserBanned" table with fields "userid" and "reason". UserBanned.userid - it is link (foreign key) on field User.id.

So, models in hiberante looks like:

@Entity
@Table(name = "user")
@DynamicInsert
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "user_id_generator")
    @SequenceGenerator(name = "user_id_generator", sequenceName = "user_id_seq")
    protected Integer id;

    @Column
    protected Integer name;

    @OneToOne (mappedBy = "user", cascade = CascadeType.ALL)
    protected UserBanned userBanned;

And UserBanned model:

@Entity
@Table(name = "userbanned")
@DynamicInsert
public class UserBanned{

    @Id
    @Column(name="userid", unique=true, nullable=false)
    @GeneratedValue(generator="gen")
    @GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="user"))
    protected Integer userid;

    @Column
    protected String reason;

    @OneToOne
    @PrimaryKeyJoinColumn
    protected User user;

And it works. I can create new user and banned user with this code:

    User user = new User();
    user.setName(name);
    UserBanned userBanned = new UserBanned ();
    userBanned.setReason(reason);

    user.setUserBanned(userBanned );
    userBanned.setUser(user);

    clientService.store(user);

But, when i try to do gson.toJson(client) i got stackoverflow error - because Gson can't handle circular references in the serialized data. But my mind cant understand why i have to set User in UserBanned?! Why i can not just have model User?

My question: how i can organize such relationship (One-To-One with foreign key) like User (there are not only UserBanned, but and UserVIP and etc entities) in hibernate?

Était-ce utile?

La solution

If you don't want UserBanned to have reference to User, you could make the UserBanned embeddable and embed it in User.

@Embeddable
public class UserBanned{
    ....
}

@Entity
@Table(name = "user")
@DynamicInsert
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "user_id_generator")
    @SequenceGenerator(name = "user_id_generator", sequenceName = "user_id_seq")
    protected Integer id;

    @Column
    protected Integer name;

    @Embedded
    protected UserBanned userBanned;

If you want the UserBanned to be in separate database-table and the table should contain reference to the user-table, I don't think you can avoid having the User in UserBanned, otherwise Hibernate won't know which User the UserBannedrefers to.

If you want just to get rid of the line userBanned.setUser(user);, you could set the User to UserBanned in Users setUserBanned(userBanned );-method.

public void setUserBanned(UserBanned userBanned) {
    this.userBanned = userBanned;
    userBanned.user(this);
}

And then excluding the field from serialization for example in way suggested in Ilyas answer.

Autres conseils

You should exclude one of cycled references (User::userBanned or UserBanned::user) from serialization and deserialization by Gson.
You can read about it in gson-documentation.

Add some annotation

  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.FIELD})
  public @interface Exlude 
  {
  }

Create ExclusionStrategy

public class MyExclusionStrategy implements ExclusionStrategy 
{
    public boolean shouldSkipClass(Class<?> clazz) 
    {
      return false;
    }

    public boolean shouldSkipField(FieldAttributes f) 
    {
      return f.getAnnotation(Exlude.class) != null;
    }
}  

Create Gson instance with GsonBuilder

Gson gson = new GsonBuilder()
        .setExclusionStrategies(new MyExclusionStrategy())
        .create();  

Annotate UserBanned::user with @Exclude annotation

@OneToOne
@PrimaryKeyJoinColumn
@Exclude
protected User user;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top