Разбивка большого класса Hibernate

У меня есть класс Hibernate, который по сути является просто оболочкой для множества коллекций.

Таким образом, класс (сильно упрощенный/псевдо) выглядит примерно так:

@Entity  
public class MyClass {

  @OneToMany  
  Map1

  @OneToMany  
  Map2

  @OneToMany   
  Map3

  AddToMap1();  
  AddToMap2();  
  AddToMap3();  
  RemoveFromMap1();  
  RemoveFromMap2();  
  RemoveFromMap3();  
  DoWhateverWithMap1();  
  DoWhateverWithMap2();  
  DoWhateverWithMap3();  

}

и т. д. Каждая из этих карт имеет несколько связанных с ней методов (добавить/удалить/допросить/и т. д.).

Как вы можете себе представить, к тому времени, когда я добавил 10-ю коллекцию или около того, класс стал немного нелепым по размеру.

То, что я хотел бы сделать, это что-то вроде строк:

 
@Entity  
public class MyClass {

  ClassWrappingMap1;

  ClassWrappingMap2;

  ClassWrappingMap3;
}

Со всеми различными методами, заключенными в эти классы:

public class ClassWrappingMap1 {

  @OneToMany
  Map

  AddToMap();  
  RemoveFromMap();  
  DoWhateverWithMap();  

}

Я подумал, что, возможно, я мог бы использовать @Embedded для этого, но, похоже, я не могу заставить его работать (Hibernate просто даже не пытается сохранить карту внутри класса-оболочки).

Кто-нибудь когда-нибудь делал что-то подобное раньше? Любые подсказки?

Большое спасибо,
Нед


person Ned Lowe    schedule 12.12.2009    source источник
comment
Можете ли вы показать, что вы пробовали с аннотацией @Embedded?   -  person Juha Syrjälä    schedule 12.12.2009
comment
Юха - я сделал именно то, что сделал ваш код (вы можете попробовать что-то вроде этого) ниже. Я разместил сообщение на форуме Hibernate - посмотрим, может ли кто-нибудь из этих парней описать передовой опыт или что-то в этом роде. Однако большое спасибо за ваши ответы.   -  person Ned Lowe    schedule 13.12.2009


Ответы (2)


В руководстве по Hibernate для аннотаций указано следующее:

Хотя аннотации Hibernate не поддерживаются спецификацией EJB3, они позволяют использовать аннотации ассоциации во встраиваемом объекте (например, @*ToOne или @*ToMany). Чтобы переопределить столбцы ассоциации, вы можете использовать @AssociationOverride.

Так что ваш подход к обертыванию должен работать.


Прежде всего, вы должны проверить все файлы журналов и т. д. на наличие связанных ошибок.

Вы можете попробовать что-то вроде этого:

  • В вашем мастер-классе (MyClass)
@Entity  
public class MyClass {

  @Embedded
  ClassWrappingMap1 map1;
}
  • И в вашем классе упаковки
@Embeddable
public class ClassWrappingMap1 {

  @OneToMany
  Map map1;

}

Обратите внимание, что ClassWrappingMap1 использует аннотацию @Embeddable. Однако, согласно документам, аннотация @Embeddable не требуется, она должна использоваться по умолчанию при использовании аннотации @Embedded.

Убедитесь, что каждый класс ClassWrappingMap сопоставляет отдельный столбец в базе данных. Также классы ClassWrappingMap не должны иметь первичный ключ (столбцы @Id или @EmbeddedId).

person Juha Syrjälä    schedule 12.12.2009
comment
Извините, но Hibernate не поддерживает @OneToMany при использовании @Embeddable. Вы видели выше и @*ToMany - person Arthur Ronald; 12.12.2009
comment
Да, я заметил это, но догадался, что это опечатка (поскольку контекст подразумевает, что это возможно — позволяет использовать аннотации ассоциации во встраиваемом объекте), и предполагалось, что это или. Возможно, следует сказать, но не, а не ни. Я полагаю, что мог бы выделить несколько вспомогательных классов, содержащих методы, и оставить @OneToManys в основном классе. Хотя кажется немного изворотливым. Любые другие предложения? Большое спасибо Артуру и Юхе за ответы. - person Ned Lowe; 12.12.2009
comment
Вернулся из отпуска - посмотрел еще раз. @Embeddable работает нормально. Причина, по которой у меня это не сработало, заключалась в том, что я программирую интерфейсы, поэтому мне нужно было добавить аннотацию @Target к фактическому классу. Повторюсь: можно поместить коллекцию в @Embeddable. - person Ned Lowe; 10.01.2010

Хотя я не знаю стратегии по умолчанию при использовании класса-оболочки, вы можете использовать Hibernate Interceptor для инициализации вашей оболочки, переопределив 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 для выполнения той же задачи. См. раздел Дизайн на основе домена с помощью Spring и Hibernate.

Если вы знаете другую стратегию, поделитесь ею с нами.

С уважением,

person Arthur Ronald    schedule 12.12.2009
comment
Артур, кажется, я понимаю, к чему вы клоните с этим предложением, но во всяком случае это еще больше усложняет жизнь :-) В худшем случае я могу поместить коллекции @OneToMany в основной класс, а затем передать ссылку на них в отдельный класс, содержащий все методы. Спасибо еще раз. - person Ned Lowe; 13.12.2009