Quebrando uma grande aula de hibernato
-
19-09-2019 - |
Pergunta
Eu tenho uma classe de hibernato que é essencialmente apenas uma embalagem em torno de muitas coleções.
Portanto, a classe é (massivamente simplificada/pseudo) algo como:
@Entity public class MyClass { @OneToMany Map1 @OneToMany Map2 @OneToMany Map3 AddToMap1(); AddToMap2(); AddToMap3(); RemoveFromMap1(); RemoveFromMap2(); RemoveFromMap3(); DoWhateverWithMap1(); DoWhateverWithMap2(); DoWhateverWithMap3(); }
etc. Cada um desses mapas possui alguns métodos associados a ele (adicione/remover/interrogar/etc).
Como você pode imaginar, quando adicionei a 10ª coleção, a classe está ficando um pouco ridícula de tamanho.
O que eu adoraria fazer é algo parecido com:
@Entity public class MyClass { ClassWrappingMap1; ClassWrappingMap2; ClassWrappingMap3; }
Com todos os vários métodos envolvidos nessas classes:
public class ClassWrappingMap1 { @OneToMany Map AddToMap(); RemoveFromMap(); DoWhateverWithMap(); }
Eu pensei que talvez pudesse usar @Embedded
Para isso, mas pareço não conseguir fazê -lo funcionar (o Hibernate simplesmente nem tenta persistir o mapa dentro do WrapperClass).
Alguém já fez algo assim antes? Alguma dica?
Muito Obrigado,
Ned
Solução
Manual de hibernação para anotações Estados seguintes:
Embora não seja apoiado pela especificação EJB3, as anotações de hibernato permitem usar anotações de associação em um objeto incorporável (ou seja, @*toone nem @*tomany). Para substituir as colunas da associação, você pode usar o @associationOverRide.
Portanto, sua abordagem de embalagem deve funcionar.
Primeiro de tudo, você deve verificar todos os arquivos de log etc para qualquer erro relacionado.
Você poderia tentar algo assim:
- Em sua aula mestre (myclass)
@Entity public class MyClass { @Embedded ClassWrappingMap1 map1; }
- E em sua aula de embrulho
@Embeddable public class ClassWrappingMap1 { @OneToMany Map map1; }
Notar que ClassWrappingMap1
usos @Embeddable
anotação. No entanto, de acordo com os documentos, a anotação @embeddable não deve ser necessária, ela deve ser padrão quando a anotação @embedded for usada.
Certifique -se de que toda classe Classwappingmap mapeie uma coluna diferente no banco de dados. Além disso, as classes ClassWrappingMap não devem ter uma chave primária (@Id
ou @EmbeddedId
colunas).
Outras dicas
Embora eu não conheça uma estratégia padrão ao usar uma classe de wrapper, você pode usar um interceptor de hibernato para inicializar o seu invólucro, substituindo carregando método. Algo como
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;
}
}
Cuida do seguinte:
Um cliente usando este interceptador deve definir a propriedade de sessão
Então seu código se parece com este
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();
Ou use a Spring AOP para realizar a mesma tarefa. Ver Design de domínio com primavera e hibernação
Se você conhece outra estratégia, compartilhe conosco.
Saudações,