2013-02-26 42 views
2

因此,讓代碼本身入手:NHibernate的子集

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(域,SITEID,ID)VALUES(,,????)]」}:{「不能添加或 更新子行:外鍵約束失敗 (projectsitedomains,約束FK_sitedomains_siteid對外 KEY(siteid)參考文獻siteid)ON DELETE CASCADE ON UPDATE CASCADE)「}

回答

3

IList<>經由<list>馬培德您應該爲索引列的映射:參照6.3. Collections of Values and Many-To-Many Associations提取:

對於索引集合(如地圖和列表),我們需要一個元素,對於列表,此列包含從零開始編號的連續整數,確保您的索引真正從零開始,如果您必須處理遺留數據

因此,在您的「sitedomains」表中必須有索引列。如果現在有索引列,你仍然可以使用IList<>,但通過包映射:

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

注:另外要確保你的集合例如實例:

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

編輯:不能使用siteidNOT NULL

你使用的映射,不包含inverse映射。 SiteDomain未引用Site。這意味着NHibernate必須將SiteDomain實體插入其表中,並在第二步中更新siteid列,並參考Site

因爲siteid列不是NULL,你會得到異常。

溶液,1)標記列作爲NULL或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" /> 

最後加入SiteDomainDomains集合時,你也必須設置SiteDomain.Site =網站

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

這將指示NHibernate什麼是siteid值,並且只會應用一個插入。 NOT NULl約束條件仍然可以應用

+0

我把它做成包,它在某些部分有幫助。目前,我使用包,當我嘗試將網站保存到數據庫時,出現異常:[Project.Core.SiteDomain#0] [SQL:INSERT INTO sitedomains(Domain,ID)VALUES(?,?)]:{ 「Field'siteid'沒有默認值」}。我該如何處理這個問題? – kseen 2013-02-26 16:32:25

+0

我更新了我的答案。問題出在您的siteid列的NOT NULL設置中。 – 2013-02-26 16:58:15

+0

請查看我爲您更新的答案。同樣的例外。也許我們應該看看列生成器? – kseen 2013-02-26 17:15:54