【问题标题】:Loading Hibernate property from an external source (HashMap)从外部源加载 Hibernate 属性 (HashMap)
【发布时间】:2010-11-26 07:32:49
【问题描述】:

我有一个与用户对象(user_from 和 user_to)关联的消息对象。我使用 Hibernate(带有 JPA 注释)将 Message 实例持久化到数据库中,并且持久化了 user_id。

User 对象也存储到数据库中,但是在获取消息时,我希望从内存中的 Map 而不是从数据库中获取 User。

原因是因为我有一些暂时性的属性无法持久化到数据库中(Facebook 数据),而当 Facebook 数据已经加载到内存中时,我不想重新向 Facebook 查询数据.

这是否可能或应该通过创建 UserType 来完成?哪个类需要定义为 UserType、Message、User 或自定义映射器?如果是自定义映射器,如何使用 JPA 注释关联映射器(我看过一个使用配置并设置 meta-type="com.example.hibernate.customtype.CustomerTypeMapper" 的示例)?

非常感谢您的帮助!

用户类别:

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

消息类:

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

【问题讨论】:

    标签: database hibernate jpa external transient


    【解决方案1】:

    使用EntityListener@PostLoad 回调方法:

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

    更新(基于下面的 cmets):

    我能理解想从内存中加载实例;我不明白您为什么要 Hibernate 这样做 :-) 这一切都归结为一个简单的选择 - 您的 User 实体至少有一些您想要的字段总是 持久保存到数据库/从数据库加载,否则不会。我认为我们谈论的是后一种情况,因为我上面提出的解决方案最适合前者。然后您的选择归结为:

    1. 根本不存在User。任何引用它的实体都只会保留用户标识符;您将使用适当的 getter 方法从缓存中检索实际的用户实例。

    2. 您可以编写一个自定义类型来自动执行上述操作。如果您有很多引用用户的实体(您将避免重复代码),这可能是有道理的。您需要实现UserType 接口;您将根据从传入的 ResultSet 中获得的标识符,从 nullSafeGet() 方法中的缓存中检索您的 User 实例;您将在 nullSageSet() 中执行相反的操作并将其持久化。

    【讨论】:

    • 谢谢。我存储了所有用户对象的地图。您的解决方案将获得属性,但仍会创建另一个用户实例。我更喜欢使用内存中已经存在的同一个 User 实例。
    • 也许我误解了你的问题。如果您想在加载用户实例时设置临时 属性,则上述解决方案是最好的。如果您尝试用内存中已经存在的 transient 实例替换已加载的实例,为什么要首先加载它?为什么它甚至被映射?将您的消息更改为将 user_id_from 和 user_id_to 映射为字符串(或任何它们)并更改 getFrom() / getTo() 访问器以从地图中获取用户实例。
    • 嗨!感谢您的答复。我确实希望 Hibernate 从内存而不是从数据库中加载整个实例。用户被加载到地图中是因为他们被放置在空间地图上(即 GEO 数据)
    • 非常感谢。如果我实现了 UserType,你认为 User 类应该实现它,Message 类,还是自定义映射器类,如果是映射器,我如何将对象与它关联?
    • 一个单独的类。 User 是该自定义类型将持续/加载的内容。 Message(或任何其他需要 User 引用的类)可以使用 @Type 注释 (docs.jboss.org/hibernate/stable/annotations/reference/en/html/…) 来指定该自定义类型(注意这是一个 HIbernate 扩展;我不确定是否有办法在纯 JPA 中执行此操作),例如@Type(type="my.custom.UserType) private User from
    【解决方案2】:

    我认为用户类型在这种情况下不会有帮助。用户类型更多地用于指定数据如何保存在数据库中,而不是 if。

    可能最简单的解决方案是将您的字段标记为瞬态,并让 getter 从某个服务中获取此数据,该服务反过来会检查内部缓存,并在缓存未命中的情况下实际查询 facebook。

    我你真的想像处理持久字段一样处理它,你应该检查休眠事件模型,找到你需要实现的事件以便插入你的逻辑。但如果你愿意,这会更有用实现一个或多或少完整的持久性解决方案,该解决方案可以持久保存在与 DB 或 XML 文件不同的东西中。

    【讨论】:

      【解决方案3】:

      使用简单的原则,我将首先提出以下建议:

      在根据需要持久化用户的同时,您当然可以在不加载用户实体的情况下查询消息。 我会做的是 UserId 字段(“to”和“from”,如果我理解正确的话),输入 Long。所以说什么用户相关的信息就在那里。

      现在,获取实际的用户实体:

      • 您可以通过查看您的 Map 来创建一个备用的 getter(瞬态,非映射的 Hibernate)来提供 User 实例。

      通常限制域模型对象(此处为持久实体)访问服务和其他代码。因此,要么将地图作为模型的一部分(它可以静态存储在模型类中)。

      • 或者,您可以让其他代码(服务等)使用 UserId 来通过 UserId 获取 User 实例,方法是调用适当的 Service(封装 Map)。

      【讨论】:

        猜你喜欢
        • 2014-12-30
        • 1970-01-01
        • 2023-03-15
        • 2016-06-18
        • 1970-01-01
        • 2018-06-25
        • 1970-01-01
        • 2013-11-19
        • 1970-01-01
        相关资源
        最近更新 更多