Nhibernate一对多关系错误

时间:2015-03-08 23:30:27

标签: c# mysql nhibernate nhibernate-mapping

我在nhibernate中保存父子关系的子记录时遇到外键错误。我使用Mysql作为数据库。 插入的外键列的值为“0”

CREATE TABLE Company(
   Id INT NOT NULL AUTO_INCREMENT,
   Name Varchar(100) NOT NULL,
   PRIMARY KEY (Id)
);

CREATE TABLE Client(
   ClientId INT NOT NULL AUTO_INCREMENT,
   CompanyId INT NOT NULL,
   Name Varchar(100) NOT NULL,
   PRIMARY KEY (ClientId),
   FOREIGN KEY(CompanyId) REFERENCES  Company(Id)
);

类别:

public class Company
{
    private IList<Client> clients = new List<Client>();

    public virtual IList<Client> Clients
    {
        get { return clients; }
        set { clients = value; }
    }

    public  virtual void AddClientToCompany(Client client)
    {
        client.Company = this; 
        clients.Add(client);
    }

    public virtual Company Company { get; set; }

    public virtual string Name { get; set; }

    public virtual int Id { get; set; }
}

public class Client
{
    public virtual Company Company { get; set; }

    public virtual string Name { get; set; }

    public virtual int CompanyId { get; set; }

    public virtual int ClientId { get; set; }   
}

 Company.hbm.xml
   <class name="ConsoleApplication1.Company, ConsoleApplication1"          table="Company">
      <id name="Id" column="Id" type="int">
       <generator class="native"></generator>
      </id>
      <property name="Name" column="Name" type="String"></property>

      <bag name="Clients" table="Client" lazy="false" cascade="all"     inverse="true">
       <key column="CompanyId"></key>
       <one-to-many class="ConsoleApplication1.Client, ConsoleApplication1"         />
   </bag>
  </class>

Client.hbm.xml

<class name="ConsoleApplication1.Client, ConsoleApplication1"   table="Client">
   <id name="ClientId" column="ClientId" type="int">
      <generator class="native"></generator>
    </id>
    <property name="Name" column="Name" type="String"></property>
    <property name="CompanyId" column="CompanyId" type="int" ></property>

    <many-to-one name="Company"  class="ConsoleApplication1.Company,    ConsoleApplication1" 
             column="CompanyId" cascade="none" insert="false"/>
 </class>

生成的SQL:

  

NHibernate:INSERT INTO公司(名称)VALUES(?p0);?p0 ='测试公司'[类型:   字符串(12)]     NHibernate:SELECT LAST_INSERT_ID()

     

NHibernate:INSERT INTO Client(Name,CompanyId)VALUES(?p0,?p1);?p0 ='Test Client'[Type:String(11)],?p1 = 0 [Type:Int32(0)]

运行时代码:

        Company company = new Company();
        company.Name = "Test Company";

        Client client = new Client();
        client.Name = "Test Client";

        company.AddClientToCompany(client);

        session.Save(company);

任何想法可能是什么问题?

1 个答案:

答案 0 :(得分:1)

这里的要点是,对于many-to-oneone-to-many,我们必须使用相同的列 "CompanyId"

Company.hbm.xml

<bag name="Clients" table="Client" lazy="false" 
     cascade="all" inverse="true" >
  <!-- wrong column name, it must be parent reference in a child table -->
  <!-- <key column="ClientId"></key> -->
  <key column="CompanyId" />
  <one-to-many class="ConsoleApplication1.Client, ConsoleApplication1" />
</bag>

Client.hbm.xml - 相同的列用于反向映射 CompanyId

<many-to-one name="Company"  
             class="ConsoleApplication1.Company, ConsoleApplication1" 
             column="CompanyId" 
             cascade="none"/>

实际上,只有一列(CompanyId)负责映射的两面......与DB中的关系相同的主体

EXTEND:

一旦我们纠正了映射,我们必须确定,我们确实在C#中设置了关系的两个方面。这是必需的,因为 inverse="true" 映射。

最好的方法是扩展 AddClientToCompany() 以分配双方:

public class Company
{
    ...
    public  virtual void AddClientToCompany(Client client)
    {
        clients.Add(client);
        // essential line
        client.Company = this;
    }
    ...

运行时代码:

var client = new Client
{
   ...
}
var company = new Company
{
   ...
}
// no company knows about client 
// and client knows abtou company
company.AddClientToCompany(client);
session.Save(company);

NHibernate现在将正确地注入具有相关实体ID的INSERT ......

毕竟,我们必须确定的是,参考映射是可编辑的 - 而不是属性:

<property name="CompanyId" column="CompanyId" type="int"
      insert="false" update="false" >
// the above must be insert and update false
// the below must be editable - it is a reference - managed by NHibernate
<many-to-one name="Company"  
      class="ConsoleApplication1.Company,    ConsoleApplication1" 
      column="CompanyId" cascade="none"/>