2

所以让我们从代码本身开始:

public class Site
{
    private Int32 id;        
    private string name;
    private IList<SiteDomain> sitedomains;

    public Site()
    {
    }

    public virtual Int32 Id
    {
        get { return id; }
        set { id = value; }
    }

    public virtual IList<SiteDomain> Domains
    {
        get { return sitedomains; }
        set { sitedomains = value; }
    }

    public virtual string Name
    {
        get { return name; }
        set { name = value; }
    }
}

public class SiteDomain
{
    private Int32 id;
    private string domain;

    public SiteDomain()
    {
    }

    public virtual Int32 Id
    {
        get { return id; }
        set { id = value; }
    }

    public virtual string Domain
    {
        get { return domain; }
        set { domain = value; }
    }
}

如您所见,我不需要从 SiteDomain 到站点的任何链接。但我想在站点实体中有一个站点域列表。

这是DDL:

CREATE TABLE `site` (
    `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(500) NOT NULL,
    PRIMARY KEY (`id`)
)
ENGINE=InnoDB;


CREATE TABLE `sitedomains` (
    `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    `siteid` BIGINT(20) UNSIGNED NOT NULL,
    `domain` VARCHAR(500) NOT NULL,
    PRIMARY KEY (`id`),
    INDEX `sitedomains_siteid` (`siteid`),
    CONSTRAINT `FK_sitedomains_siteid` FOREIGN KEY (`siteid`) REFERENCES `site` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
ENGINE=InnoDB;

我目前得到的映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="PhoneTracking.Core" assembly="PhoneTracking.Core">
  <class name="Site" table="site">
    <id name="Id" type="Int32">
      <column name="ID" not-null="true" />
    </id>
    <property name="Name" type="AnsiString" />
    <list name="Domains" cascade="all">
      <key column="SiteId" />
      <index />
      <one-to-many class="SiteDomain" />
    </list>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="PhoneTracking.Core" assembly="PhoneTracking.Core">
  <class name="SiteDomain" table="sitedomains">
    <id name="Id" type="Int32">
      <column name="ID" not-null="true" />
    </id>
    <property name="Domain" type="AnsiString" />
  </class>
</hibernate-mapping>

当我得到一个站点时,它检索得很好。它带有所有相关站点的域。但是后来我将新站点保存回数据库,它只保存站点本身,而不插入站点的域。

我应该如何做对?

我知道 NHibernate 的 ISet。我只是想让它成为 IList,因为它对我来说更舒服。


编辑:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="PhoneTracking.Core" assembly="PhoneTracking.Core">
  <class name="SiteDomain" table="sitedomains">
    <id name="Id" type="Int32">
      <column name="ID" not-null="true" />
    </id>
    <property name="Domain" type="AnsiString" />
    <many-to-one name="Site" column="siteid" />
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="PhoneTracking.Core" assembly="PhoneTracking.Core">
  <class name="Site" table="site">
    <id name="Id" type="Int32">
      <column name="ID" not-null="true" />
    </id>
    <property name="Name" type="AnsiString" />
    <bag name="Domains" inverse="true" cascade="all">
      <key column="SiteId" />
      <one-to-many class="SiteDomain" />
    </bag>
  </class>
</hibernate-mapping>

更新了 SiteDomain 类:

public class SiteDomain
{
    private Int32 id;
    private string domain;
    private Site site;

    public SiteDomain()
    {
    }

    public virtual Int32 Id
    {
        get { return id; }
        set { id = value; }
    }

    public virtual Site Site
    {
        get { return site; }
        set { site = value; }
    }

    public virtual string Domain
    {
        get { return domain; }
        set { domain = value; }
    }
}

这是我尝试保存新动态创建的条目的方法:

ITransaction tx = session.BeginTransaction();

Site s = new Site();
s.Name = StringGenerator.RandomString(20) + " site";
s.Domains = new List<SiteDomain>();
s.Domains.Add(new SiteDomain { Site = s, Domain = StringGenerator.RandomString(20) + ".com" });   

session.SaveOrUpdate(s);                
tx.Commit();       

现在我得到一个例外:

{"无法插入:[Project.Core.SiteDomain#0][SQL: INSERT INTO sitedomains (Domain, siteid, ID) VALUES (?, ?, ?)]"} : {"无法添加或更新子行:外键约束失败 ( project. sitedomains, CONSTRAINT FK_sitedomains_siteidFOREIGN KEY ( siteid) REFERENCES site( id) ON DELETE CASCADE ON UPDATE CASCADE)"}

4

1 回答 1

3

IList<>通过映射时<list>,您应该为索引列提供映射:参见6.3。值集合和多对多关联。提炼:

对于像地图和列表这样的索引集合,我们需要一个元素。对于列表,此列包含从零开始编号的连续整数。如果您必须处理遗留数据,请确保您的索引确实从零开始

因此,“sitedomains”表中还必须有索引列。如果现在有索引列,您仍然可以使用IList<>但通过包映射:

<bag name="Domains" cascade="all">
      <key column="SiteId" />    
      <one-to-many class="SiteDomain" />
</bag>

注意:还要确保您的集合已实例化,例如:

public Site()
{
   sitedomains = new List<SiteDomain>();
}

编辑:不能使用siteid NOT NULL

您使用的映射不包含inverse映射。SiteDomain不引用Site. 这意味着 NHibernate 必须将SiteDomain实体插入到其表中,并且在第二步中,它siteid使用对Site.

因为该siteid列不是 NULL,所以您会遇到异常。

解决方案,1)将列标记为 NULL 或 2)更改映射以引用Site来自 SiteDomain 的映射并将映射更改为反向,如下所示:

 <bag name="Domains" cascade="all" inverse="true">
    <key column="SiteId" />    
    <one-to-many class="SiteDomain" />
  </bag>

并在站点映射中使用多对一

<many-to-one name="Site" column="siteid" />

最后,在添加SiteDomainDomains集合时,您还必须设置 SiteDomain.Site = site

site.Domains.Add(siteDomain);
siteDomain.Site = site;

这将指示 NHibernate 什么是 siteid 值,并且只会应用一个插入。并且仍然可以应用 NOT NULl 约束

于 2013-02-26T16:18:56.433 回答