2008-12-30 88 views
7

我目前使用NHibernate作为我的数据访问层,使用Fluent NHibernate为我创建映射文件。我有两个类,TripItem和TripItemAttributeValue,它们之间有多对多的关系。NHibernate不支持多对多关系

的映射如下:

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

在我的应用程序某些时候,我从数据库中读取现有属性,将其添加到tripItem.Attributes,然后保存tripItem对象。最后,TripItems_TripItemAttributeValues_Link从不会获取任何新记录,从而导致关系不被保留。

如果有帮助,这些都是功能NHibernate生成的映射文件,这些类:

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

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

什么我错在这里做什么?

回答

8

@efdee

我有同样的问题,并在此度过了差不多两天。我有一个多对多的关系,链接表也没有更新。我是NHibernate的新手,只是想学习它,所以把我说的一切都放在一边。

事实证明,它不是流利的NHibernate,也不是映射,但我不理解NHibernate如何与多对多协同工作。在多对多关系中,如果两个实体上的集合都没有填充,NHibernate不会将数据保存到链接表。

比方说,我有一个多一对多的关系这个实体:


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

当我添加对Contact.Locations的位置,我必须确保该联系人也存在内部的位置.Contacts。

所以要添加一个位置我有我的联系人类中的此方法。


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

这似乎解决了我的问题,但就像我说我只是拿起NHibernate并学习它,可能有更好的方法。如果有人有更好的解决方案,请发布。

这是我指出来检查两个集合的帖子:http://www.coderanch.com/t/217138/Object-Relational-Mapping/link-table-of-ManyToMany-annotation

2

我不知道你怎么用流利的NHibernate做,但你需要设置袋子上的Cascade选项(TripItems)。像往常一样,Ayende's got a useful post about cascade options

从快速谷歌,我建议你试试:

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

大卫·肯普具有正确的事:你想级联添加到您的袋子。

我一直手工编辑(和手工创建)映射文件,所以我的自然倾向是把它放在那里。你可以做如下:

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

我发现,让我的班“纯”和藏在心里中的.hbm.xml文件与NHibernate做使我的解决方案更清洁。那样的话,如果我想使用一个新的ORM软件,我只需要替换映射文件,而不要重写这些类。我们使用我们的单元测试来测试类,并给xml提供可测试性,尽管我的确有点像Fluent NHibernate的方法。

0

恐怕Cascade.All()不是真的解决我的问题 - 这是我尝试过的一件事。问题不在于添加到集合中的项目未保存 - 它们在添加到集合时已存在于数据库中。只是链接表中的条目没有被创建。此外,我认为Cascade.All()也会导致子项被删除,这在我的场景中是不可取的行为。我尝试过使用Cascade.SaveUpdate(),但正如我已经指出的那样,这解决了一些并不是真正的问题:-)

但是,为了确保,我会重试此解决方案并让您知道结果。

至于保持类纯净,这与Fluent NHibernate是100%的情况。您创建的类映射是C#代码文件,与您的实体类一起使用,非常像.hbm.xml文件。

+0

对我来说也是一样 - 级联不是我想要的,也没有帮助。法拉盛是答案! – 2011-04-15 15:22:09

1

我恰好具有我同样的问题,但我一直在使用NHibernate.JetDriver。我尝试使用推荐的答案没有任何成功。有谁知道NHibernate.JetDriver是否对多对多有限制?

这里是我的HBM文件,以防有人碰巧有兴趣在审查他们一会儿:

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

1

我知道了,我希望这帮助别人。问题是我对两个包都有inverse ='true'。如果您阅读下面的摘录,您会注意到仅需要将其中一个袋子设置为true即可:

请注意使用inverse =“true”。此设置再一次告诉NHibernate忽略对类别集合所做的更改,并使用关联的另一端 - 项目集合 - 作为应与数据库同步的表示。

0

我也在为此而苦苦挣扎,并因为我的烦恼而出现了完全不同的原因。在我的例子中,如果我有一个没有任何多对多关系的对象,我可以直接调用saveOrUpdate,并且都是好的。但是,如果我有任何多对多的关系,我必须确保我的saveOrUpdate调用在BeginTransaction和CommitTransaction中。我对流利的Nhibernate很新,很抱歉,如果这很明显。但它不是我。

7

调用Session.Flush()或使用事务。

+0

谢谢! 我有同样的问题。我为关系的一方调用了Session.SaveOrUpdate(实体)。但是这并没有创建链接表。调用Session.Flush()解决了这个问题。 – 2010-08-27 02:52:36

2

我也有同样的问题 - 多对多的加入数据没有被保留。我已经复制了另一个多对一关系(修改为多对多rel)的映射,但保留了inverse =“true”属性。当我删除这个属性时,问题就解决了。

相关问题