I have a Message object associated with a User object (user_from and user_to). I persist the Message instances into a database using Hibernate (with JPA annotations) and the user_id is persisted.
The User object is also stored to the database, but when fetching messages I would like the User to be fetched from a Map in memory instead of from the database.
The reason is because I have some transient attributes that I can't persist to the database (Facebook data), and when the Facebook data is already loaded in memory, I don't want to re-query Facebook for the data.
Is this possible or should be done by creating a UserType? Which class needs to be defined as the UserType, the Message, the User or a custom mapper? If a custom mapper, how do I associate the mapper using JPA annotations (I have seen an example that uses configurations and sets meta-type="com.example.hibernate.customtype.CustomerTypeMapper")?
Thank you very much for your help!
User class:
@Entity(name="com.company.model.user")
@Table(name = "user")
public class User {
private Long id;
private Long fbId;
private String firstName;
private URL picThumbnailUrl;
//...
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getFbId() {
return fbId;
}
public void setFbId(Long fbId) {
this.fbId = fbId;
}
@Transient @FacebookField
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Transient @FacebookField
public URL getPicThumbnailUrl() {
return picThumbnailUrl;
}
public void setPicThumbnailUrl(URL picThumbnailUrl) {
this.picThumbnailUrl = picThumbnailUrl;
}
//....
}
Message class:
@Entity(name="com.company.model.message")
@Table(name = "message")
public class Message {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
@JoinColumn(name="user_id_from")
private User from;
@ManyToOne
@JoinColumn(name="user_id_to")
private User to;
private String text;
//...
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getFrom() {
return from;
}
public void setFrom(User from) {
this.from = from;
}
public User getTo() {
return to;
}
public void setTo(User to) {
this.to = to;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
//....
}
Use an EntityListener or a @PostLoad
callback method:
@PostLoad
public void updateFacebookFields() {
// get stuff from HashMap
setFirstName("whatever");
setPicThumbnailUrl(myUrl);
}
Update (based on comments below):
I can understand you wanting to load instance from memory; I don't understand why you'd want Hibernate to do it :-) It all really comes down to a simple choice - either your User
entity has at least some fields you'd want to always persist to / load from the database or it doesn't. I take it we're talking about the latter scenario because the former is best served by the solution I've proposed above. Your choices then boil down to:
Not persisting User
at all. Any entity referencing it would persist only user identifier; you will retrieve the actual user instance from your cache in appropriate getter method.
You can write a custom type that would automate the above for you. That may make sense if you have lots of entities referencing users (you'll avoid repeated code). You'll need to implement UserType interface; you'll retrieve your User
instance from your cache from within nullSafeGet()
method based on identifier you get from passed in ResultSet; you'll do the opposite in nullSageSet()
and persist it back.