Pergunta

Eu tenho um relacionamento muitos-para-um entre objetos Product e Supplier. Eu preciso ser capaz de Supplier sem apagar os Products que pertencem a ele.

Aqui está uma versão simplificada de classes:

public class Supplier {
    public virtual IList<Product> Products { get; protected set; }
}

public class Product {
    // Product belongs to a Category but Supplier is optional
    public virtual Supplier Supplier { get; set; }
    public virtual Category Category { get; set; }
}

Eu estou usando FluentNHibernate, mas aqui estão os mapeamentos que produz:

<bag name="Products" cascade="save-update" inverse="true">
      <key column="SupplierID" />
      <one-to-many class="Me.Product, Me, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>

<many-to-one name="Supplier" column="SupplierID" />

Isso cria uma chave estrangeira na tabela Produtos, então quando eu tentar fazer uma linha reta de eliminação num Fornecedor recebo um erro de restrição de chave estrangeira. Eu tentei mudar cascata para 'todos', na esperança de que ele só pode excluir o relacionamento, mas apagou todos os produtos e seus outros objetos associados.

A única maneira que eu posso ver para resolver isso agora é iterar a coleção Produtos de fornecedor e definir a propriedade Fornecedor como nulo. Existe uma maneira eu posso conseguir este comportamento através do mapeamento?

Foi útil?

Solução

As propriedades de mapeamento só têm efeito quando a entidade está realmente carregado, e quando você não está consultando através HQL. Como exemplo, se você especificar Cascade=ALL, se você excluir um fornecedor com o "delete from Supplier where id=:id" consulta, você provavelmente terá a mesma falha FK constrangimento, porque o hql não aciona (programáticos) cascatas.

Parece que os produtos são o lado possuir da relação, que é bom. Eu acho que você tem duas opções:

  • Código algum método do fornecedor para percorrer todos os produtos e definir fornecedor do produto para null, e usar este método antes de excluir quaisquer Fornecedores
  • Antes de emitir um Fornecedor apagar, verifique se o DAO define fornecedor do produto para nula

Exemplo:

public int Delete(Supplier s) {
    return Session.CreateQuery("udpate Product set Supplier = null where Supplier = :supplier")
        .SetParameter("supplier", s)
        .ExecuteUpdate();
}

Outras dicas

Não faça isso.

Você tem uma afirmação implícita ou explícita em seu modelo que todos os produtos têm um Fornecedor. A chave estrangeira está lá para fazer cumprir esta condição. Remoção do Fornecedor, mantendo os produtos viola o seu modelo e provavelmente fará com que grande parte do seu código, o que depende este sempre ser verdadeiro, a falhar.

A única coisa que você pode fazer, você já descobriu: para cada produto que tem este fornecedor, você pode definir o produto nulo Fornecedor. Isso não vai violar sua condição, mas é o mesmo que dizer "não sabemos quem é o fornecedor deste produto é" e pode causar falhas de código.

Por que você quer fazer isso?

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