Hibernato-Limpendo uma coleção com Orfão All-Delete e, em seguida, acrescentando a ele causa restantriolationException

StackOverflow https://stackoverflow.com/questions/2065254

  •  20-09-2019
  •  | 
  •  

Pergunta

Eu tenho essas entidades

class Foo{
    Set<Bar> bars;
}

class Bar{
    Foo parent;
    String localIdentifier;
}

Com este mapeamento (desculpe, sem anotações, estou antiquado):

<class name="Foo">
    ...
    <set name="bars" cascade="all-delete-orphan" lazy="false" inverse="true">
        <key>...</key>
        <one-to-many class="Bar"/>
    </set>
</class>


<class name="Bar">
    ...
    <property name="localIdentifier" column="local_identifier"/>
    <many-to-one name="parent" column="parent_id" />
</class>

Eu também tenho uma restrição única em 2 colunas: local_identifier e parent_id (Não é uma restrição única em cada um, mas uma única restrição única contendo ambos, por exemplo, nº 2 linhas com o mesmo pai e o mesmo identificador local são permitidas)

alter table bar add constraint unique_bar unique (parent_id, local_identifier)

E este código que os usa:

//foo is persistent, foo id = 1
Bars bars = foo.getBars();
bars.clear(); // bars contained 1 item [parent_id = 1, local_identifier = "a"]
Bar newBar = new Bar();
newBar.setParent(foo);
newBar.setLocalIdentifier("a");
bars.add(newBar);

Agora, por algum motivo, o Hibernate não executa as coisas na ordem em que foram chamadas. Não executa o clear() (excluir) antes do add() (inserir) Mas vice -versa, ele primeiro tenta inserir, obtendo um ConstraintViolationException

Eu sei adicionando um pouco session.flush() depois bars.clear(); , poderia consertar isso, mas, neste caso, não tenho acesso à sessão de uma maneira não feia.

Então é o rubor é a única solução? Ou existe uma versão de hibernato que respeita a ordem das ações?

Atualizar:A propósito, a desreferência da coleção resultará em uma hibernateException de https://www.hibernate.org/117.html#a3:

Eu recebo HibernateException: Não desrefereça uma coleção com cascade = "All-Delete-Orphan" Isso acontecerá se você carregar um objeto com uma coleção Cascade = "All-Delete-Orphan" e depois remover a referência à coleção. Não substitua esta coleção, use Clear () para que o algoritmo de delicadeza órfão possa detectar sua alteração.

Foi útil?

Solução

Eu acho que não há alternativa à descarga

A partir de aqui:

Hibernate está violando uma restrição única!

O Hibernate não é tão inteligente com restrições únicas quanto com as chaves estrangeiras. Às vezes, você pode precisar dar uma pequena dica.

Uma violação única de restrição pode ocorrer se dois objetos estiverem sendo atualizados, um está "liberando" um valor e o outro é "obter" o mesmo valor. Uma solução alternativa é para rubor() A sessão manualmente depois de atualizar o primeiro objeto e antes de atualizar o segundo.

(Esse tipo de problema ocorre raramente na prática.)

Outras dicas

Se você quiser evitar a liberação da sessão aqui, tente substituir a lista inteira (new List<Bar>() ao invés de Clear()). O Hibernate deve realmente remover todos os itens de uma só vez antes de adicionar novos. Apenas uma tentativa, não tenho certeza se funciona.

Se você estiver usando o Oracle, também poderá usar restrições diferíveis para adiar a verificação das restrições até que a transação seja cometida. Não tenho certeza se/como isso é suportado por outros bancos de dados.

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