所以让我们从代码本身开始:
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到站点的链接。但是我想在site实体中有一个站点域的列表。
这里是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>
当我得到一个站点时,它检索得非常好。它带有所有关联站点的域。但之后我将新站点保存回数据库它只保存站点本身而不插入站点的域。
我该怎么做才对?
我知道伊贝内特的伊斯兰教。我只是想让它更舒服些。
编辑:
<?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>
更新的站点域类:
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
站点域(域、站点ID、ID)值(?,?,?)]“}:{”无法添加或
更新子行:外键约束失败
(
project
sitedomains
,constraintFK_sitedomains_siteid
外来更新时删除级联上的键(
siteid
)引用site
(id
)级联)“}
最佳答案
通过IList<>
映射<list>
时,应为索引列提供映射:请参见6.3. Collections of Values and Many-To-Many Associations。摘录:
对于索引集合(如映射和列表),我们需要一个元素。对于列表,此列包含从零开始编号的连续整数。如果必须处理遗留数据,请确保索引真正从零开始
所以,在“sitedomains”表中还必须有索引列。如果现在有索引列,您仍然可以使用IList<>
但通过bag映射:
<bag name="Domains" cascade="all">
<key column="SiteId" />
<one-to-many class="SiteDomain" />
</bag>
注意:还要确保集合已实例化,例如:
public Site()
{
sitedomains = new List<SiteDomain>();
}
编辑:不能使用
siteid
不为空您使用的映射不包含
inverse
映射。SiteDomain
不引用Site
。这意味着nhibernate必须将SiteDomain
实体插入到它的表中,并且在第二步中,它使用对siteid
的引用更新Site
列。因为
siteid
列不为空,所以会出现异常。解决方案,1)将列标记为空,或2)更改映射以引用来自sitedomain的
Site
,并将映射更改为如下所示的逆映射: <bag name="Domains" cascade="all" inverse="true">
<key column="SiteId" />
<one-to-many class="SiteDomain" />
</bag>
并在站点映射中使用多对一
<many-to-one name="Site" column="siteid" />
最后,在将
SiteDomain
添加到Domains
集合时,还必须设置sitedomain.site=sitesite.Domains.Add(siteDomain);
siteDomain.Site = site;
这将指示nhibernate什么是siteid值,并且只应用一个insert。并且仍然可以应用not null约束