Loading Hibernate property from external source (HashMap)

I have a Message object associated with a User object (user_from and user_to). I store Message instances in a database using Hibernate (with JPA annotations) and the user_id is preserved.

The custom object is also stored in the database, but when retrieving messages, I would like the User to be retrieved from the Map in memory and not from the database.

The reason is that I have some transient attributes that I cannot store in the database (Facebook data), and when the Facebook data is already loaded into memory, I don’t want to re-query Facebook for the data.

Is this possible or should it be done by creating a UserType? Which class should be defined as UserType, Message, User, or custom mapper? If a custom mapper, how do I map the mapping using JPA annotations (I've seen an example that uses config and sets the meta type = "com.example.hibernate.customtype.CustomerTypeMapper")?

Many thanks 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;
    }
    //....
}

      

+2


source to share


3 answers


Use EntityListener or callback method @PostLoad

:

@PostLoad
public void updateFacebookFields() {
  // get stuff from HashMap
  setFirstName("whatever");
  setPicThumbnailUrl(myUrl);
}

      

Update (based on comments below):



I can understand you to load an instance from memory; I don't understand why you need Hibernate :-) It all really comes down to a simple choice - either your object User

has at least some fields that you want to always be saved / loaded from the database or not. I suppose we are talking about the latter scenario because the former is best served by the solution I suggested above. Then your options boil down to this:

  • Don't save User

    at all. Any object referencing it will retain only the user ID; you will get the actual user instance from your cache in the corresponding getter method.

  • You can write a custom type that automates the above for you. This can make sense if you have a lot of objects referencing users (you avoid duplicate code). You will need to implement the UserType interface; you will retrieve an instance User

    from your cache from a method nullSafeGet()

    based on the ID you get from passed to the ResultSet; you will do the opposite in nullSageSet()

    and save it back.

+1


source


I don't think a custom type would help in this case. User type is more for specifying how data is stored in the database, rather than.

Probably the simplest solution would be to mark your field as transient and let the recipient get this data from some service, which in turn will check the internal cache and, in case of a cache miss, actually ask facebook.



I really want to treat it as a persistent field, you should check the hibernate event model to find the events you need to implement in order to hook your logic up. But that would be more complete if you want to implement a more or less complete save solution that is saved in something other than DB or XML files.

0


source


Using the principle of simplicity, I would like to start with a suggestion:

With constant use of Users, you can request messages without loading user objects. What I would do would be to have the UserId fields ("to" and "from" if I understand correctly) printed Long. Thus, there is information about which user is related.

Now, to get the actual user object:

  • You can make an alternate getter (transient, not mapped to Hibernate) that would provide a user instance by looking at your map.

It is typical to restrict access to services and other codes to domain model objects (persistent object here). So either you make the map part of your model (it can be stored statically in the model class).

  • Or, you let other codes (Services, etc.) use the UserId to get the user instance through the UserId by calling the appropriate service (which encapsulates the map).
0


source







All Articles