NHibernare la relazione multi-to-one eliminando solo il genitore
-
03-07-2019 - |
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?
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?