Reputation: 1182
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?
Upvotes: 1
Views: 971
Reputation: 202
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 UserBanned
refers 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.
Upvotes: 2
Reputation: 29673
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;
Upvotes: 2