【问题标题】:Breaking up a large Hibernate class分解一个大的 Hibernate 类
【发布时间】:2009-12-12 10:16:18
【问题描述】:

我有一个 Hibernate 类,它本质上只是对大量集合的包装。

所以这个类(大量简化/伪)类似于:

@实体 公共类 MyClass { @OneToMany 地图1 @OneToMany 地图2 @OneToMany 地图3 AddToMap1(); AddToMap2(); AddToMap3(); RemoveFromMap1(); RemoveFromMap2(); RemoveFromMap3(); DoWhateverWithMap1(); DoWhateverWithMap2(); DoWhateverWithMap3(); }

等等。然后,这些地图中的每一个都有一些与之关联的方法(添加/删除/询问/等)。

你可以想象,当我添加第 10 个左右的集合时,这个类的规模变得有点荒谬了。

我想做的事情是这样的:

@实体 公共类 MyClass { 类WrappingMap1; 类WrappingMap2; 类WrappingMap3; }

所有各种方法都包含在这些类中:

公共类 ClassWrappingMap1 { @OneToMany 地图 添加地图(); RemoveFromMap(); DoWhateverWithMap(); }

我想也许我可以为此使用@Embedded,但我似乎无法让它工作(Hibernate 甚至没有尝试将 Map 持久化到 wrapperClass 中)。

以前有人做过这样的事情吗?有什么提示吗?

非常感谢,
内德

【问题讨论】:

  • 你能用@Embedded 注释说明你尝试了什么吗?
  • Juha - 我完全按照你的代码(“你可以尝试这样的事情”)做了什么。我已经在 Hibernate 论坛上发帖了——让我们看看这些人中是否有人可以描述最佳实践之类的。非常感谢您的回答。

标签: hibernate wrapper hibernate-mapping


【解决方案1】:

Hibernate manual for annotations 声明如下:

虽然 EJB3 规范不支持,但 Hibernate Annotations 允许您在可嵌入对象(即 @*ToOne 或 @*ToMany)中使用关联注释。要覆盖关联列,您可以使用@AssociationOverride。

所以你的包装方法应该有效。


首先,您应该检查所有日志文件等是否有任何相关错误。

你可以试试这样的:

  • 在您的大师班(MyClass)中
@实体 公共类 MyClass { @嵌入式 ClassWrappingMap1 map1; }
  • 在你的包装类中
@可嵌入 公共类 ClassWrappingMap1 { @OneToMany 地图地图1; }

注意ClassWrappingMap1 使用@Embeddable 注释。但是,根据文档,应该不需要 @Embeddable 注释,使用 @Embedded 注释时应该是默认的。

确保每个 ClassWrappingMap 类映射数据库中的不同列。 ClassWrappingMap 类也不应该有主键(@Id@EmbeddedId 列)。

【讨论】:

  • 抱歉,Hibernate 在使用 @Embeddable 时不支持 @OneToMany。你在上面看到过“也没有@*ToMany”
  • 是的,我注意到了,但猜这是一个错字(因为上下文暗示它是可能的 - “允许您在可嵌入对象中使用关联注释”)并且它应该说“或” .也许它应该说“但不是”而不是“也不”。我想我可以分解一些包含方法的辅助类,并将 @OneToManys 留在主类中。不过似乎有点狡猾。还有其他建议吗?非常感谢 Arthur 和 Juha 的回复。
  • 假期回来——又看了一遍。 @Embeddable 工作正常。它对我不起作用的原因仅仅是因为我正在对接口进行编程,所以我需要在实际类中添加一个 @Target 注释。重申一下 - 可以将 Collection 放在 @Embeddable 中。
【解决方案2】:

虽然我不知道使用包装器类时的默认策略,但您可以使用 Hibernate 拦截器通过覆盖 onLoad 方法来初始化包装器。类似的东西

public class WrapperInterceptor extends EmptyInterceptor {

    private Session session;

    public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        if (entity instanceof MyClass) {
             MyClass myClass = (MyClass) entity;

             Query query = session.createQuery(<QUERY_TO_RETRIEVE_WRAPPED_ENTITY_GOES_HERE>);

             WrappedEntity wrappedEntity = query.list().get(0);

             myClass.setWrapperClass(new WrapperClass(wrappedEntity));
        }
    }

    public void setSession(Session session) {
        this.session = session;
    }
}

注意以下事项:

使用此拦截器的客户端必须设置 Session 属性

所以你的代码看起来像这样

WrapperInterceptor interceptor = new WrapperInterceptor();

Session session = sessionFactory().openSession(interceptor);

Transaction tx = session.beginTransaction();

interceptor.setSession(session);

MyClass myClass = (MyClass) session.get(newItem, myClassId); // Triggers onLoad event

tx.commit();
session.close();

或者使用 Spring AOP 来完成同样的任务。见Domain Driven Design with Spring and Hibernate

如果您知道其他策略,请与我们分享。

问候,

【讨论】:

  • 亚瑟 - 我想我知道你的建议是什么 - 但如果这会让生活变得更加复杂 :-) 最坏的情况 - 我可以将 @OneToMany 集合放在主类中,然后将对它的引用传递给包含所有方法的单独类。再次感谢。
猜你喜欢
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-23
  • 2015-04-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多