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>

サイトを取得すると、非常によく取得されます。関連するすべてのサイトのドメインが付属しています。しかし、新しいサイトをDBに保存し、サイトのドメインを挿入せずにサイト自体のみを保存します。

どのように正しくすればよいですか?

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は使用できません

使用したマッピングにはマッピングが含まれていませんinverseSiteDomainを参照しませんSite。つまり、NHibernate はSiteDomainエンティティをテーブルに挿入する必要があり、2 番目のステップで、siteidへの参照を使用して列を更新しますSite

列がNOT siteidNULL であるため、例外が発生します。

解決策として、1) 列を NULL としてマークするか、2) マッピングをSite変更して SiteDomain から参照し、マッピングを次のように逆に変更します。

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

サイト マッピングで多対 1 を使用する

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

最後にコレクションに追加するときは、SiteDomainSiteDomain.Site Domains= site も設定する必要があります。

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

これは NHibernate に siteid 値を指示し、1 つの挿入だけが適用されます。そして、NOT NULl 制約がまだ適用される可能性があります

于 2013-02-26T16:18:56.433 に答える