C# NHibernate 一对多映射问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/645579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 11:35:20  来源:igfitidea点击:

NHibernate one-to-many mapping problem

c#.netnhibernatenhibernate-mappingone-to-many

提问by Nazgul

I have to map two simple table with a foreign key relationship. One of the tables is Contactcontaining columns id(primary key of type int),name, addressand guid(newly added and is not the primary key). The other one is phone__numbercontaining columns id(primary key of type int), contact___id(foreign key of id in contact table) and phone__number.

我必须用外键关系映射两个简单的表。其中一个表是Contact包含列id(int 类型的主键)、nameaddressguid(新添加的,不是主键)。另一个是phone__number包含列id(int 类型的主键)、contact___id(联系人表中 id 的外键)和phone__number

The mapping file for Contact table is as below :

Contact 表的映射文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="OfflineDbSyncWithNHibernate" default-lazy="true" namespace="OfflineDbSyncWithNHibernate.Models">
  <class name="Contact" table="Contact">
    <id name="Id" column="Id" type="int">
      <generator class="native" />
    </id>

    <property name="Name" column="name" type="string"/>
    <property name="Address" column="address" type="string"/>
    <property name="Guid" column="guid" type="string"/>

    <set lazy="true" batch-size="6" table="phone_number" name="PhoneNumbers" fetch="join" inverse="false" cascade="all" >
      <key foreign-key="FK_contact_phone_number" column="contact_id"/>
      <one-to-many class="PhoneNumber" />
    </set>

  </class>
</hibernate-mapping>

The mapping file for Phone_number table is :

Phone_number 表的映射文件是:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="OfflineDbSyncWithNHibernate" default-lazy="true" namespace="OfflineDbSyncWithNHibernate.Models">
  <class name="PhoneNumber" table="phone_number">
    <id name="Id" column="Id" type="int">
      <generator class="native" />
    </id>
    <property name="ContactId" column="contact_id" />
    <property name="Number" column="phone_number" />
  </class>
</hibernate-mapping>

The Contact and PhoneNumber classes are :

Contact 和 PhoneNumber 类是:

namespace OfflineDbSyncWithNHibernate.Models
{
    public class Contact
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual string Address { get; set; }
        public virtual string Guid { get; set; }
        public virtual PhoneNumbers PhoneNumbers { get; set; }
    }
}

namespace OfflineDbSyncWithNHibernate.Models
{
    public class PhoneNumber
    {
        public virtual int Id { get; set; }
        public virtual int ContactId { get; set; }
        public virtual string Number { get; set; }
    }
}

namespace OfflineDbSyncWithNHibernate.Models
{
    public class PhoneNumbers : List<PhoneNumber>
    {
    }
}

When I load the contact and phone_numbers separately it works, but after adding the set element to get a one-to-many relationship nhibernate is giving an error :

当我分别加载联系人和电话号码时,它可以工作,但是在添加 set 元素以获得一对多关系后,nhibernate 出现错误:

NHibernate.MappingException: Invalid mapping information specified for type OfflineDbSyncWithNHibernate.Models.Contact, check your mapping file for property type mismatches

NHibernate.MappingException:为类型 OfflineDbSyncWithNHibernate.Models.Contact 指定的映射信息无效,请检查您的映射文件中的属性类型不匹配

I am new to nHibernate so I am not sure if there is a mistake in the set element or I should not even be using it. Any help will be appreciated.

我是 nHibernate 的新手,所以我不确定 set 元素中是否有错误,或者我什至不应该使用它。任何帮助将不胜感激。

采纳答案by Brijesh Mishra

Just remeber this

只要记住这个

  • Bag is implemented using IList
  • Set is implemented using ISet
  • List is implemented using ArrayList or List
  • Map is implemented using HashedTable or IDictionary
  • Bag 是使用 IList 实现的
  • Set 是使用 ISet 实现的
  • List 使用 ArrayList 或 List 实现
  • Map 使用 HashedTable 或 IDictionary 实现

If you want to use IList use first rule i.e change your hbm.xml to use Bag instead of Set also your Phonenumbers class should inherit from IList not List, if you want to use List you will need to change your mapping file to use List instead of Set.

如果你想使用 IList 使用第一条规则,即改变你的 hbm.xml 使用 Bag 而不是 Set 你的 Phonenumbers 类应该继承 IList 而不是 List,如果你想使用 List 你需要改变你的映射文件来使用 List集。

回答by Andy White

I think your PhoneNumbers class needs to inherit from a subtype of Iesi.Collections.ISet. I don't think there is a "Set" type provided in .NET by default. See hibernate FAQ

我认为您的 PhoneNumbers 类需要从Iesi.Collections.ISet. 我认为 .NET 中默认没有提供“Set”类型。请参阅休眠常见问题解答

The <set> maps to an Iesi.Collections.ISet. That interface is part of the Iesi.Collections assembly distributed with NHibernate.

<set> 映射到 Iesi.Collections.ISet。该接口是随 NHibernate 分发的 Iesi.Collections 程序集的一部分。

回答by Frederik Gheysels

Your collection-type should be an interface, because NHibernate will provide it's own type that implements that interface when an object is retrieved from the DB.

您的集合类型应该是一个接口,因为当从数据库检索对象时,NHibernate 将提供它自己的类型来实现该接口。

If you define your collection as

如果您将集合定义为

public virtual ISet<PhoneNumber> Phonenumbers = new HashedSet<Phonenumber>();

Then I think it will work.

然后我认为它会起作用。

In order to better control the access to your collection, you can modify your Contact class like this:

为了更好地控制对您的集合的访问,您可以像这样修改您的 Contact 类:

public class Contact
{
    public virtual int Id {get;set;}
    ..

    private ISet<Phonenumber> _phoneNumbers = new HashedSet<PhoneNumber>();

    public ReadOnlyCollection<Phonenumber> PhoneNumbers
    {
        get 
        {
           return new List<Phonenumber>(_phoneNumbers).AsReadOnly();
        }
    }

    public void AddPhonenumber( Phonenumber n )  
    {
        n.Contact = this;
        _phoneNumbers.Add(n);
    }

    public void RemovePhoneNumber( PhoneNumber n )
    {
        ...
    }
}

Then, you have to make sure that in your mapping of the Contact class, you specify that NHibernate should access the field _phoneNumbers instead of the property PhoneNumber:

然后,您必须确保在 Contact 类的映射中,指定 NHibernate 应该访问字段 _phoneNumbers 而不是属性 PhoneNumber:

<set name="PhoneNumbers" access="field.camelcase-underscore" ... >
   ...
</set>