Domanda

Il mio modello contiene una classe Section che ha un elenco ordinato di Statics che fanno parte di questa sezione.Tralasciando tutte le altre proprietà, l'implementazione del modello si presenta così:

public class Section
{
    public virtual int Id { get; private set; }
    public virtual IList<Static> Statics { get; private set; }
}

public class Static
{
    public virtual int Id { get; private set; }
}

Nel database, la relazione è implementata come uno-a-molti, dove la tabella Static ha una chiave esterna che punta a Section e una colonna intera Position per memorizzare la sua posizione di indice nell'elenco di cui fa parte.

La mappatura viene eseguita in Fluent NHibernate in questo modo:

public SectionMap()
{
    Id(x => x.Id);
    HasMany(x => x.Statics).Cascade.All().LazyLoad()
            .AsList(x => x.WithColumn("Position"));
}

public StaticMap()
{
    Id(x => x.Id);
    References(x => x.Section);
}

Ora sono in grado di caricare i file esistenti Statics, e sono anche in grado di aggiornarne i dettagli.Tuttavia, non riesco a trovare un modo per aggiungerne di nuovi Statics ad a Section, e fare in modo che la modifica venga mantenuta nel database.Ho provato diverse combinazioni di:

  • mySection.Statics.Add(myStatic)
  • session.Update(mySection)
  • session.Save(myStatic)

ma il più vicino che ho ottenuto (usando le prime due istruzioni) è un'eccezione SQL che legge:"Impossibile inserire il valore NULL nella colonna 'Posizione'".Chiaramente un INSERT viene tentato qui, ma NHibernate non sembra aggiungere automaticamente la posizione dell'indice all'istruzione SQL.

Che cosa sto facendo di sbagliato?Mi manca qualcosa nelle mie mappature?Devo esporre il file Position colonna come proprietà e assegnarle un valore personalmente?

MODIFICARE: Apparentemente tutto funziona come previsto, se rimuovo il file NOT NULL vincolo sul Static.Position colonna nel database.Immagino che NHibernate effettui l'inserimento e subito dopo aggiorni la riga con a Position valore.

Sebbene questa sia una risposta alla domanda, non sono sicuro che sia la migliore.Preferirei il Position colonna non annullabile, quindi spero ancora che ci sia un modo per fare in modo che NHibernate fornisca un valore per quella colonna direttamente nel INSERT dichiarazione.

Pertanto, la questione è ancora aperta.Altre soluzioni?

È stato utile?

Soluzione

Quando si utilizza una bidirezionale relazione uno-a-molti in NHibernate una delle estremità deve essere "inverso". Le migliori pratiche è quello di impostare la fine con la collezione come inversa, dal momento che evita inutili istruzioni SQL e consente la colonna id essere "non null".

sezione 6.4 della documentazione riesce a trovare la seguente nota:

  

Molto Nota importante: se la colonna di un'associazione viene dichiarata NOT NULL, NHibernate può causare violazioni di vincoli quando si crea o aggiorna l'associazione. Per evitare questo problema, è necessario utilizzare un'associazione bidirezionale con i tanti valore finale (il set o in borsa) contrassegnato come inverse = "true". Vedere la discussione delle associazioni bidirezionali più avanti in questo capitolo.

Quindi, è necessario aggiungere .Inverse () per la mappatura hasMany in SectionMap.

public SectionMap()
{
    Id(x => x.Id);
    HasMany(x => x.Statics)
        .Cascade.All()
        .LazyLoad()
        .Inverse()
        .AsList(x => x.WithColumn("Position"));
}

Si potrebbe anche probabilmente vuole un Add e Remove metodo su Sezione, che imposta / resetta il riferimento della statica così come l'aggiunta / rimozione della statica da / per la propria collezione:

public virtual void AddStatic(Static static)
{
    Statics.Add(static);
    static.Section = this;
}


public virtual void RemoveStatic(Static static)
{
    Statics.Remove(static);
    static.Section = null;
}

Questi metodi si assicura i riferimenti sono tenuti accurate su entrambi i lati della relazione.

6.8 dei documenti NHibernate non supporta rapporti bidirezionali quando si usano le collezioni indicizzate:

  

Si prega di notare che NHibernate non supporta associazioni bidirezionali uno-a-molti con una collezione indicizzata (lista, mappa o array) come la fine "molti", è necessario utilizzare un set o mappatura borsa.

Quindi, se si sta ancora problemi, considerare l'utilizzo di un rapporto unidirezionale invece di un bidirezionale, tuttavia, che potrebbe significare che la colonna di chiave esterna deve essere annullabile (secondo la nota all'inizio del post). In caso contrario, potrebbe essere necessario mappare la vostra collezione come una borsa o un insieme invece di una lista.

Altri suggerimenti

Nella mensa del Static si dispone di un campo chiamato "Idsezione" o qualcosa di simile. Lasciate che questo campo sia annullabile:. NHibernate prima aggiunge il nuovo record, quindi aggiorna l'id di riferimento

Ho scoperto che nel mio db e mi sorprende troppo: perché l'NH non piace riferimenti di tabella corretta a livello di database

?

Ho pensato di aggiungere i miei $ 0,02, solo perché sono venuto qui cercando di risolvere il tuo problema e sembra che nessuna delle risposte funzioni davvero.

Sei quasi arrivato alla tua soluzione.La tua mappatura per HasMany è corretta.Il problema è, come hai detto, la Posizione non viene aggiornata nel database (FWIW quando la imposti su null, "funziona" solo perché NULL viene inserito nel DB;per me non funziona davvero ;)).

Lo trovo un po' strano, devi mappare la posizione anche sulla tua classe Static e ovviamente includere una proprietà Position su Static.Tuttavia, non vuoi che la proprietà Position sia scrivibile, perché il suo valore è determinato dalla posizione di Static nell'elenco.

Aggiungi quanto segue a Statico

public virtual int Position 
{
    get 
    {
        // Will throw exception if Section is null
        // or Section.Statics is null...
        return Section.Statics.IndexOf(this);
    }
    protected set 
    {
    }
}

Con quello nella colonna Posizione il db verrà aggiornato (ricordati di mappare la tua Posizione nella tua StaticMap).

Immagino che il proxy NHib di Static possa aggiornare il campo Posizione a seconda della sua posizione nell'elenco (con una magia più grande di quella che possiedo) e che quindi venga salvato nel db.

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