Pregunta

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?

¿Fue útil?

Solución

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.

Otros consejos

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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top