Domanda

Attualmente sto usando NHibernate come livello di accesso ai miei dati, usando Fluent NHibernate per creare i file di mappatura per me. Ho due classi, TripItem e TripItemAttributeValue, che hanno una relazione molti-a-molti tra loro.

La mappatura è la seguente:

public class TripItemMap : ClassMap<TripItem2>
{
    public TripItemMap()
    {
        WithTable("TripItemsInt");
        NotLazyLoaded();

        Id(x => x.ID).GeneratedBy.Identity().WithUnsavedValue(0);
        Map(x => x.CreateDate, "CreatedOn").CanNotBeNull();
        Map(x => x.ModifyDate, "LastModified").CanNotBeNull();

        /* snip */

        HasManyToMany<TripItemAttributeValue>(x => x.Attributes).AsBag()
            .WithTableName("TripItems_TripItemAttributeValues_Link")
            .WithParentKeyColumn("TripItemId")
            .WithChildKeyColumn("TripItemAttributeValueId")
            .LazyLoad();
    }
}

public class TripItemAttributeValueMap : ClassMap<TripItemAttributeValue>
{
    public TripItemAttributeValueMap()
    {
        WithTable("TripItemAttributeValues");

        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Name).CanNotBeNull();

        HasManyToMany<TripItem2>(x => x.TripItems).AsBag()
            .WithTableName("TripItems_TripItemAttributeValues_Link")
            .WithParentKeyColumn("TripItemAttributeValueId")
            .WithChildKeyColumn("TripItemId")
            .LazyLoad();
    }
}

Ad un certo punto della mia applicazione prendo gli attributi esistenti dal database, li aggiungo a tripItem.Attributes, quindi salvo l'oggetto tripItem. Alla fine, TripItems_TripItemAttributeValues_Link non ottiene mai nuovi record, con il risultato che le relazioni non persistono.

Se aiuta, questi sono i file di mappatura generati da Fluent NHibernate per queste classi:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" assembly="ETP.Core" namespace="ETP.Core.Domain">
  <class name="TripItem2" table="TripItemsInt" xmlns="urn:nhibernate-mapping-2.2" lazy="false">
    <id name="ID" column="ID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="CreateDate" column="CreatedOn" type="DateTime" not-null="true">
      <column name="CreatedOn" />
    </property>
    <property name="ModifyDate" column="LastModified" type="DateTime" not-null="true">
      <column name="LastModified" />
    </property>
    <bag name="Attributes" lazy="true" table="TripItems_TripItemAttributeValues_Link">
      <key column="TripItemId" />
      <many-to-many column="TripItemAttributeValueId" class="ETP.Core.Domain.TripItemAttributeValue, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bag>
  </class>
</hibernate-mapping>

e

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" assembly="ETP.Core" namespace="ETP.Core.Domain">
  <class name="TripItemAttributeValue" table="TripItemAttributeValues" xmlns="urn:nhibernate-mapping-2.2">
    <id name="Id" column="Id" type="Int32">
      <generator class="identity" />
    </id>
    <property name="Name" column="Name" length="100" type="String" not-null="true">
      <column name="Name" />
    </property>
    <bag name="TripItems" lazy="true" table="TripItems_TripItemAttributeValues_Link">
      <key column="TripItemAttributeValueId" />
      <many-to-many column="TripItemId" class="ETP.Core.Domain.TripItem2, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bag>
  </class>
</hibernate-mapping>

Cosa sto facendo di sbagliato qui?

È stato utile?

Soluzione

@efdee

Stavo avendo lo stesso problema e ci ho passato quasi due giorni. Avevo molte relazioni e la tabella dei collegamenti non veniva aggiornata. Sono nuovo di NHibernate, sto solo cercando di impararlo, quindi prendi tutto ciò che dico con un pizzico di sale.

Bene, si è scoperto che non è fluente NHibernate, né la mappatura, ma io non capisco come funziona NHibernate con molti-a-molti. In una relazione molti-a-molti se le raccolte su entrambe le entità non sono popolate, NHibernate non mantiene i dati nella tabella dei collegamenti.

Diciamo che ho queste entità in una relazione molti-a-molti:


partial class Contact
{
   public string ContactName {get; set;}
   public IList Locations {get; set;}

}

partial class Location
{
   public string LocationName {get; set;}
   public string LocationAddress {get;set;}
   public IList Contacts {get;set;}
}

quando aggiungo una posizione a Contact.Locations, devo assicurarmi che il contatto sia presente anche all'interno della posizione. Contatti.

quindi per aggiungere una posizione ho questo metodo nella mia classe Contact.


public void AddLocation(Location location)
        {
            if (!location.Contacts.Contains(this))
            {
                location.Contacts.Add(this);
            }
            Locations.Add(location);
        }

Questo sembra aver risolto il mio problema, ma come ho detto sto solo raccogliendo NHibernate e imparandolo, forse c'è un modo migliore. Se qualcuno ha una soluzione migliore, si prega di pubblicare.

Questo è il post che mi ha indicato di controllare entrambe le raccolte: http://www.coderanch.com/t/217138/Object-Relational-Mapping/link-table-of-ManyToMany-annotation

Altri suggerimenti

Chiama Session.Flush () o usa la transazione.

Non sono sicuro di come lo fai con Fluente NHibernate, ma è necessario impostare l'opzione Cascade sulla borsa ( TripItems ). Come al solito, Ayende ha un post utile sulle opzioni a cascata .

Da un veloce Google, ti suggerisco di provare:

HasManyToMany<TripItem2>(x => x.TripItems).AsBag()
        .WithTableName("TripItems_TripItemAttributeValues_Link")
        .WithParentKeyColumn("TripItemAttributeValueId")
        .WithChildKeyColumn("TripItemId")
        .LazyLoad()
/*-->*/ .Cascade.All(); /*<-- this is the bit that should make it work */

Ho anche avuto lo stesso problema: i dati di unione per i molti-a-molti non erano persistenti. Avevo copiato la mappatura da un'altra relazione molti-a-uno (modificata per una relazione molti-a-molti) ma conservavo un inverso = "vero"; attributo. Quando ho rimosso questo attributo il problema è stato risolto.

David Kemp ha ragione: vuoi aggiungere una cascata alla tua borsa.

Ho sempre modificato a mano (e creato a mano) i file di mappatura, quindi la mia naturale inclinazione è quella di metterli lì. Puoi farlo come segue:

<bag name="TripItems" lazy="true" table="TripItems_TripItemAttributeValues_Link" cascade="all">
  <key column="TripItemAttributeValueId" />
  <many-to-many column="TripItemId" class="ETP.Core.Domain.TripItem2, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>

Ho scoperto che mantenere le mie classi "pure" e mantenere tutto a che fare con nHibernate nel file .hbm.xml mantiene la mia soluzione più pulita. In questo modo, se c'è un nuovo software ORM che voglio usare, sostituisco solo i file di mappatura e non riscrivo le classi. Usiamo i nostri test unitari per testare le classi e dare testabilità all'xml, anche se mi piacciono i metodi di Fluent NHibernate.

Sto riscontrando esattamente lo stesso problema ma sto usando NHibernate.JetDriver. Ho provato a utilizzare la risposta consigliata senza successo. Qualcuno sa se NHibernate.JetDriver ha una limitazione rispetto a molti-a-molti?

Ecco i miei file hbm nel caso in cui qualcuno fosse interessato a esaminarli per un momento:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Ace.Docs.Core.Domain" assembly="Ace.Docs.Core">
<class name="Ace.Docs.Core.Domain.Address, Ace.Docs.Core" table="Addresses" lazy="true">
    <id name="Id" column="ID">
        <generator class="identity" />
    </id>
    <property name="Address1" column="Address1" />
    <property name="Address2" column="Address2" />
    <property name="City" column="City" />
    <property name="EmailAddress" column="EmailAddress" />
    <property name="Phone1" column="Phone1" />
    <property name="Phone2" column="Phone2" />
    <property name="PostalCode" column="PostalCode" />
    <property name="StateOrProvince" column="StateOrProvince" />
    <many-to-one name="AddressTypeMember" column="AddressTypeID" class="AddressType" />
    <bag name="HasPersonalInfo" table="Link_PersonalInfo_Addresses" lazy="true" cascade="save-update" inverse="true" >
        <key column="AddressID"></key>
        <many-to-many column="PersonalInfoID" class="PersonalInfo" />
    </bag>
</class>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Ace.Docs.Core.Domain" assembly="Ace.Docs.Core">
<class name="Ace.Docs.Core.Domain.PersonalInfo, Ace.Docs.Core" table="PersonalInfo" lazy="true">
    <id name="Id" column="ID">
        <generator class="identity" />
    </id>
    <property name="Prefix" column="Prefix" />
    <property name="FirstName" column="FirstName" />
    <property name="MiddleName" column="MiddleName" />
    <property name="LastName" column="LastName" />
    <property name="SIN" column="SIN" />
    <property name="Birthdate" column="Birthdate" />
    <property name="Note" column="Notes" />
    <bag name="HasAddress" table="Link_PersonalInfo_Addresses" lazy="true" cascade="save-update" inverse="true" >
        <key column="PersonalInfoID"></key>
        <many-to-many column="AddressID" class="Address" />
    </bag>
</class>

Ce l'ho e spero che questo aiuti qualcun altro là fuori. Il problema è che avevo inverso = "vero" su entrambi i sacchetti. Se leggi il seguente estratto noterai che è necessario impostare il valore inverso su true solo su uno dei sacchetti:

Nota l'uso di inverse = " true " ;. Ancora una volta, questa impostazione indica a NHibernate di ignorare le modifiche apportate alla raccolta di categorie e di utilizzare l'altra estremità dell'associazione - la raccolta di elementi - come rappresentazione che deve essere sincronizzata con il database.

Temo che Cascade.All () non sia davvero la soluzione al mio problema: è stata una delle cose che ho provato. Il problema non è che gli elementi aggiunti alla raccolta non vengono salvati: sono già nel database al momento in cui vengono aggiunti alla raccolta. È solo che le voci nella tabella dei collegamenti non vengono create. Inoltre, penso che Cascade.All () provocherebbe anche la cancellazione di elementi figlio, il che non è un comportamento desiderabile nel mio scenario. Ho provato ad usare Cascade.SaveUpdate (), ma come ho sottolineato, questo risolve qualcosa che non è davvero il mio problema :-)

Tuttavia, per essere sicuro, riproverò questa soluzione e ti farò sapere il risultato.

Per quanto riguarda il mantenimento delle classi pure, questo è il 100% nel caso di Fluente NHibernate. I mapping delle classi che crei sono file di codice C # che affiancano le tue classi di entità, più o meno come farebbero i file .hbm.xml.

Anche io stavo lottando con questo, e ho avuto una ragione completamente diversa per i miei problemi. Nel mio esempio, se avessi un oggetto senza relazioni molti-a-molti, potrei semplicemente chiamare saveOrUpdate e tutto andrebbe bene. Ma se avessi avuto rapporti molti-a-molti, dovevo assicurarmi che la mia chiamata saveOrUpdate fosse all'interno di BeginTransaction e CommitTransaction. Sono molto nuovo con Nhibernate, quindi scusate se è ovvio. Ma non era per me.

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