Pergunta

Atualmente estou usando o NHibernate como minha camada de acesso a dados, usando Fluent NHibernate para criar os arquivos de mapeamento para mim. Eu tenho duas classes, TripItem e TripItemAttributeValue, que têm uma relação muitos-para-muitos entre eles.

O mapeamento é o seguinte:

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

Em algum ponto da minha aplicação eu buscar atributos existentes do banco de dados, adicioná-los à tripItem.Attributes, em seguida, salvar o objeto tripItem. No final, o TripItems_TripItemAttributeValues_Link nunca recebe quaisquer novos registros, resultando em relações não sendo persistiram.

Se ajudar, estes são os arquivos de mapeamento gerados pela Fluent NHibernate para estas classes:

<?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>

O que estou fazendo de errado aqui?

Foi útil?

Solução

@efdee

Eu estava tendo o mesmo problema e passou quase dois dias sobre este assunto. Eu tinha um relacionamento muitos para muitos ea tabela de link não estava sendo atualizado também. Eu sou novo para NHibernate, apenas tentando aprender de modo a ter tudo o que digo com um grão de sal.

Bem descobriu-se que não é Fluent NHibernate, nem o mapeamento, mas me não compreender como NHibernate trabalha com muitos-para-muitos. Em uma relação muitos-para-muitos, se coleções em ambas as entidades não são preenchidas, NHibernate não persistir dados para a tabela de link.

Vamos dizer que eu tenho este entidades em um relacionamento muitos-para-muitos:


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 eu adicionar em um local para Contact.Locations, eu tenho que ter certeza de que o contato é também presentes location.Contacts dentro.

para adicionar um local eu tenho esse método dentro da minha classe Contact.


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

Esta parece ter resolvido o meu problema, mas como eu disse eu só estou pegando NHibernate e aprendê-lo, pode ser que há uma maneira melhor. Se alguém tiver uma solução melhor, por favor poste.

Este é o post que me apontou para verificar ambas as coleções: http://www.coderanch.com/t/217138/Object-Relational-Mapping/link-table-of-ManyToMany-annotation

Outras dicas

Chamada Session.flush () ou o uso de transação.

Eu não sei como você faz isso com Fluent NHibernate, mas você precisa definir a opção Cascade no saco (TripItems). Como de costume, Ayende tem uma pós úteis sobre opções cascata .

A partir de uma rápida no Google, eu sugiro que você tente:

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

Eu também tive o mesmo problema - os dados unindo para a many-to-many não foi persistiu. I tinha copiado do mapeamento a partir de uma outra relação de muitos para um (modificou-lo por um rel n para n) mas retido um inverso = atributo "verdadeiro". Quando eu removi esse atributo, o problema foi resolvido.

David Kemp tem direito:. Deseja adicionar uma cascata para o seu saco

Eu sempre mão-editado (e mão-criado) os arquivos de mapeamento, por isso a minha inclinação natural é para colocá-lo lá. Você pode fazer isso da seguinte forma:

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

Eu descobri que manter 'puro' e manter tudo minhas aulas a ver com nHibernate no arquivo .hbm.xml mantém minha solução mais limpa. Dessa forma, se há um novo software ORM Eu quero usar, eu apenas substituir os arquivos de mapeamento, e não reescrever as classes. Nós usamos nossos testes de unidade para testar as classes e dar capacidade de teste para o xml, embora eu tipo de como os métodos de Fluent NHibernate.

Eu estou tendo exatamente o mesmo problema, mas eu tenho usado o NHibernate.JetDriver. Eu tentei usar a resposta recomendado sem qualquer sucesso. Alguém sabe se o NHibernate.JetDriver tem uma limitação com relação a muitos-para-muitos?

Aqui estão os meus arquivos HBM no caso de alguém passa a ser interessado em rever-los por um 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>

Eu tenho isso e eu espero que isso ajude alguém lá fora. A questão é que eu tinha = inversas 'verdadeiro' em ambos os sacos. Se você ler o trecho abaixo você vai notar que é preciso haver set inversa à verdade em apenas um dos sacos:

Observe o uso de inverse = "true". Mais uma vez, este ajuste diz NHibernate para ignorar as alterações feitas à coleção categorias e usar a outra extremidade da associação - a coleção de itens -. Como a representação que deve ser sincronizado com o banco de dados

Eu tenho medo Cascade.All () não é realmente a solução para o meu problema - que era uma das coisas que eu tentei. O problema não é que os itens adicionados à coleção não são salvos - eles já estão no banco de dados no momento em que eles estão sendo adicionados à coleção. É que as entradas na tabela de link não estão sendo criados. Além disso eu acho Cascade.All () também causa itens filhos para ser excluído, o que não é um comportamento desejável no meu cenário. Eu tentei usar Cascade.SaveUpdate (), mas como eu já fora apontado, isso resolve algo que não é realmente o meu problema: -)

No entanto, para ter certeza, vou repetir esta solução e deixá-lo saber o resultado.

Como para manter as classes pura, isto é 100% o caso com Fluent NHibernate. Os mapeamentos de classe criados são arquivos de código C # que vão junto com suas classes de entidade, muito bonito como arquivos .hbm.xml faria.

Eu estava lutando com isso também, e veio por uma razão completamente diferente para os meus problemas. No meu exemplo, se eu tivesse um objeto sem qualquer relacionamento muitos-para-muitos que eu poderia apenas chamar saveOrUpdate, e tudo estaria bem. Mas se eu tivesse quaisquer relações muitos-para-muitos, eu tinha que ter certeza de que o meu apelo saveOrUpdate estava dentro de um BeginTransaction e CommitTransaction. Eu sou muito novo para Nhibernate fluente, então desculpas se isso é óbvio. Mas não era para mim.

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