Domanda

Ho una relazione molti-a-uno tra gli oggetti Product e Supplier . Devo essere in grado di eliminare Supplier senza eliminare i Product che appartengono ad esso.

Ecco una versione semplificata delle classi:

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; }
}

Sto usando FluentNHibernate, ma qui ci sono le mappature che produce:

<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" />

Questo crea una chiave esterna nella tabella Prodotti, quindi quando provo a fare una cancellazione diretta su un Fornitore ottengo un errore di vincolo di chiave esterna. Ho provato a cambiare la cascata in "all", nella speranza che potesse solo eliminare la relazione, ma ha eliminato tutti i prodotti e gli altri oggetti associati.

L'unico modo in cui posso vedere per risolvere questo problema in questo momento è iterare la raccolta Prodotti del Fornitore e impostare la proprietà del Fornitore su null. Esiste un modo per ottenere questo comportamento attraverso la mappatura?

È stato utile?

Soluzione

Le proprietà del mapping hanno effetto solo quando l'entità è effettivamente caricata e quando non si esegue una query tramite HQL. Ad esempio, se specifichi Cascade = ALL , se elimini un fornitore con la query " elimina dal fornitore dove id =: id " , probabilmente otterrai il stesso errore del vincolo FK, perché hql non attiva cascate (programmatiche).

Sembra che i Prodotti siano il lato proprietario della relazione, il che è positivo. Penso che tu abbia due scelte:

  • Codifica un metodo sul fornitore per scorrere tutti i prodotti e impostare il fornitore del prodotto su null e utilizzare questo metodo prima di eliminare qualsiasi fornitore
  • Prima di emettere l'eliminazione di un fornitore, assicurarsi che il DAO imposti il ??fornitore del prodotto su null

Esempio:

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

Altri suggerimenti

NON FARLO.

Nel tuo modello hai un'affermazione implicita o esplicita che tutti i prodotti hanno un fornitore. La chiave esterna è lì per applicare questa condizione. La rimozione del Fornitore mantenendo i Prodotti viola il tuo modello e probabilmente causerà il fallimento di gran parte del codice, che si basa sul fatto che ciò è sempre vero.

L'unica cosa che puoi fare, hai già scoperto: per ogni Prodotto che ha questo Fornitore, puoi impostare null il Fornitore del Prodotto. Ciò non violerà la tua condizione, ma equivale a dire "non sappiamo chi è il fornitore di questo prodotto" e può causare errori di codice.

Perché vuoi farlo?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top