Pergunta

Eu tenho esse problema por um longo tempo agora, eu tenho pesquisado na web e SO dentro e para fora e não encontrou uma solução ainda. Eu espero que você pode me ajudar com isso.

Eu tenho uma relação pai-filho entre duas entidades como o seguinte:

@Entity
public class Parent {
    // ...

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private Set<Child> children = new HashSet<Child>();

    // ...
}

@Entity
public class Child {
    // ...

    @ManyToOne(fetch = FetchType.LAZY)
    private Parent parent;

    // ...
}

A coisa é que quando eu criar uma nova criança e atribuí-lo a um pai, o pai não é atualizado quando se está no cache já.

 Parent parent = new Parent();
 em.persist(parent);

 // ...

 Child child = new Child();
 child.setParent(parent);
 em.persist(child);

 parent.getChildren().size(); // returns 0

Eu tentei uso @PreUpdate para adicionar automaticamente a criança para o pai quando a criança é mantido, mas no caso em que temos 2 gerentes entidade em 2 linhas diferentes (como no JBoss), o problema ainda existe, até chamamos em.refresh(parent)

Portanto, a pergunta é - existe uma maneira de suavemente eliminar o problema e garantir que parent.getChildren() sempre retornar a lista up-to-date de crianças

?
Foi útil?

Solução

A maioria ORM vai se comportar desta forma.

O objeto no cache não é atualizado no banco de dados (uma leitura extra que não é necessário). Também acho que o modelo de objeto ea persistência como separado. ou seja, manter o seu modelo de objeto consistente com si mesmo e não contam com o mecanismo de persistência para fazer isso por você.

Então, se você quer que o objeto a ser adicionado à coleção, em seguida, fazer isso no código "setParent".

A melhor prática neste caso é de fato para fazer um lado da relação de fazer todo o trabalho e deixar o outro lado adiar para ele. Também gostaria de sugerir o uso de acesso de campo em vez de acesso método, de que maneira você pode personalizar os métodos com maior flexibilidade.

Adicionar um método para o pai chamada addChild

 public void addChild(Child child) {
    child.setParent0(this);
    getChildren().add(individualNeed);
 }

e, em seguida, fazer setParent em crianças:

public void setParent(Parent parent) {
   parent.addChild(child);
}

setParent0 em crianças é a stter propriedade para pai em criança.

public void setParent0(Parent parent) {
   this.parent = parent;
}

Eu também gostaria de sugerir que o método "getChildren" retornar uma coleção imutável para que os desenvolvedores não inadvertantly não usar este método (eu aprendi da maneira mais difícil em tudo isso).

Mais uma coisa, você deve ter código de verificação nula e outras peças defensivas no código acima, deixei-o para fora para maior clareza.

Outras dicas

Pretty certeza que seu problema aqui é suas configurações de Cascade.

@Entity
public class Parent {
   // ...

   @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, 
      cascade = {CascadeType.REMOVE, CascadeType.PERSIST})
   @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
   private Set<Child> children = new HashSet<Child>();

   // ...
}

@Entity
public class Child {
    // ...

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    private Parent parent;

    // ...
}

Usando essas configurações em cascata em cascata persistem e atualizações para objetos filho.

por exemplo.

Parent parent = new Parent();
em.persist(parent);

// ...

Child child = new Child();
child.setParent(parent);
em.persist(child); //will cascade update to parent

parent.getChildren().size(); // returns 1

ou

Parent parent = new Parent();
Child child = new Child();
parent.setChild(parent);
em.persist(parent); //will cascade update to child

child.getParent(); // returns the parent

Mais informações sobre este podem ser encontradas em Hibernate Annotations

Quanto à sua questão com o cache, este é um problema muito comum quando você tem várias VMs em execução contra o mesmo banco de dados com caches separados. É chamado de "desvio cache".

A maioria das implementações de cache-friendly de hibernação (ehcache, OSCache e SwarmCache) têm um cache distribuído built-in que pode ser usado para sincronizar os caches. O cache distribuído, geralmente, envia mensagens de multicast atualizar o estado do cache. Fazendo uma segunda despejo cache de nível por SessionFactory.evict (Classe, ID), por exemplo, fará com que uma mensagem de invalidação ao ser enviado para as outras caches no cluster que vai invalidar quaisquer outras cópias desse objecto em outros caches.

Dependendo da sua implantação, o multicast pode ou não ser aceitável para você. Se não for você pode precisar usar uma solução-cache único como memcached.

Eu, pessoalmente, encontrou a configuração do eh de cache de cache distribuído muito simples.

cache de EH discute o problema em um pouco mais detalhadamente aqui: http://ehcache.org/documentation/ distributed_caching.html

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top