Nhibernate Cascade=无未按预期工作

Nhibernate Cascade=无未按预期工作,nhibernate,Nhibernate,我有两个类,供应商和联系人。供应商是联系人的父级。供应商和联系人之间存在一对多关系。我已将供应商和公司之间的级联关系设置为“无”。这意味着(至少对我而言)当我更改供应商的联系人并保存供应商时,此保存操作不应层叠到联系人,因此,我对联系人所做的任何更改都不应保留到数据库中 然而,情况并非如此。当我更改联系人的名字并保存其父联系人时,保存操作将级联到联系人。例如,使用下面的测试函数,我看到一个名为FirstName=“This\u new\u first\u name\u should\u not\

我有两个类,供应商和联系人。供应商是联系人的父级。供应商和联系人之间存在一对多关系。我已将供应商和公司之间的级联关系设置为“无”。这意味着(至少对我而言)当我更改供应商的联系人并保存供应商时,此保存操作不应层叠到联系人,因此,我对联系人所做的任何更改都不应保留到数据库中

然而,情况并非如此。当我更改联系人的名字并保存其父联系人时,保存操作将级联到联系人。例如,使用下面的测试函数,我看到一个名为FirstName=“This\u new\u first\u name\u should\u not\u saved”的联系人。起初,我并不希望看到这种更改持续到数据库中

我只是误解了cascade的工作原理,还是我的代码有问题

Test.cs

[Test]
        public void RemoveManyToOneAssociation()
        {
            var container = BuildContainer();
            var vendorRepo = container.Resolve<Repository<Vendor>>(); //Get respository
            var contactRepo = container.Resolve<Repository<Contact>>(); //Get repository


            var vendor = vendorRepo.FirstOrDefault();
            var contact = vendor.Contacts.FirstOrDefault();
            contact.FirstName = "This_new_first_name_should_not_be_saved"; 
            vendor.Contacts.Remove(contact);
            vendorRepo.Save(vendor); 
            //The saving action above should not cascade to contacts because we have set cascade to "none"

        }
[测试]
公共无效删除ManyToneAssociation()
{
var container=BuildContainer();
var vendorRepo=container.Resolve();//获取响应
var contactRepo=container.Resolve();//获取存储库
var vendor=vendorRepo.FirstOrDefault();
var contact=vendor.Contacts.FirstOrDefault();
contact.FirstName=“此新名称不应保存”;
供应商。联系人。删除(联系人);
供应商保存(供应商);
//上述保存操作不应级联到联系人,因为我们已将级联设置为“无”
}
Vendor.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="DataAccess"
                   namespace="DataAccess">


  <class name="Vendor">
    <id name="Id" type="int" unsaved-value="0">
      <generator class="hilo" />
    </id>
    <property name="VendorName" />
    <set name="Contacts" inverse="true" cascade="none">
      <key column="VendorID" />
      <one-to-many class="Contact"/>
    </set>
    <many-to-one name="Company" column="CompanyID"></many-to-one>
  </class>

</hibernate-mapping>
 <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                       assembly="DataAccess"
                       namespace="DataAccess">

      <class name="Contact">
    <id name="Id" type="int">
      <generator class="hilo" />
    </id>
    <property name="FirstName" />
    <property name="LastName" />
    <many-to-one name="Vendor" class="Vendor" column="VendorID"></many-to-one>
  </class>

</hibernate-mapping>

Contact.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="DataAccess"
                   namespace="DataAccess">


  <class name="Vendor">
    <id name="Id" type="int" unsaved-value="0">
      <generator class="hilo" />
    </id>
    <property name="VendorName" />
    <set name="Contacts" inverse="true" cascade="none">
      <key column="VendorID" />
      <one-to-many class="Contact"/>
    </set>
    <many-to-one name="Company" column="CompanyID"></many-to-one>
  </class>

</hibernate-mapping>
 <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                       assembly="DataAccess"
                       namespace="DataAccess">

      <class name="Contact">
    <id name="Id" type="int">
      <generator class="hilo" />
    </id>
    <property name="FirstName" />
    <property name="LastName" />
    <many-to-one name="Vendor" class="Vendor" column="VendorID"></many-to-one>
  </class>

</hibernate-mapping>

Vendor.cs

public class Vendor : Entity<int>
    {
        public Vendor()
        {
        }

        public Vendor(string name)
        {                       
            VendorName = name;
        }


        public virtual string VendorName { set; get; }

        public virtual ISet<Contact> Contacts { set; get; }

        public virtual Company Company { set; get; }

        public virtual void CopyTo(Vendor target)
        {
            target.VendorName = VendorName;
            target.Company = Company;
        }
    }
public class Contact : Entity<int>
    {
        public Contact()
        {
            //it's not the best practice to initialize virtual properties in constructor but we're controlling 
            //the inheritance in this so doing this should be fine
            // http://stackoverflow.com/a/469577/89605
            FirstName = "";
            LastName = "";
        }

        public Contact(string firstName, string lastName)
        {
            FirstName = firstName;
            LastName = lastName;
        }

        public virtual string FirstName { set; get; }
        public virtual string LastName { set; get; }
        public virtual Vendor Vendor { set; get; }

        public virtual void CopyTo(Contact contact)
        {
            contact.FirstName = FirstName;
            contact.LastName = LastName;
        }
    }
公共类供应商:实体
{
公共供应商()
{
}
公共供应商(字符串名称)
{                       
VendorName=名称;
}
公共虚拟字符串VendorName{set;get;}
公共虚拟ISet联系人{set;get;}
公共虚拟公司公司{set;get;}
公共虚拟无效复制到(供应商目标)
{
target.VendorName=VendorName;
目标公司=公司;
}
}
Contact.cs

public class Vendor : Entity<int>
    {
        public Vendor()
        {
        }

        public Vendor(string name)
        {                       
            VendorName = name;
        }


        public virtual string VendorName { set; get; }

        public virtual ISet<Contact> Contacts { set; get; }

        public virtual Company Company { set; get; }

        public virtual void CopyTo(Vendor target)
        {
            target.VendorName = VendorName;
            target.Company = Company;
        }
    }
public class Contact : Entity<int>
    {
        public Contact()
        {
            //it's not the best practice to initialize virtual properties in constructor but we're controlling 
            //the inheritance in this so doing this should be fine
            // http://stackoverflow.com/a/469577/89605
            FirstName = "";
            LastName = "";
        }

        public Contact(string firstName, string lastName)
        {
            FirstName = firstName;
            LastName = lastName;
        }

        public virtual string FirstName { set; get; }
        public virtual string LastName { set; get; }
        public virtual Vendor Vendor { set; get; }

        public virtual void CopyTo(Contact contact)
        {
            contact.FirstName = FirstName;
            contact.LastName = LastName;
        }
    }
公共类联系人:实体
{
公众联络()
{
//在构造函数中初始化虚拟属性不是最佳做法,但我们可以控制它
//这样做的继承应该是好的
// http://stackoverflow.com/a/469577/89605
FirstName=“”;
LastName=“”;
}
公共联系人(字符串firstName,字符串lastName)
{
名字=名字;
LastName=LastName;
}
公共虚拟字符串FirstName{set;get;}
公共虚拟字符串LastName{set;get;}
公共虚拟供应商{set;get;}
公共虚拟无效复制到(联系人)
{
contact.FirstName=FirstName;
contact.LastName=LastName;
}
}
更新 *Repository.cs*

公共类存储库,其中T:class
{
非公开会议;
公共存储库(ISession会话)
{
_会话=会话;
}
公共虚拟T GetById(int id)
{
return _session.Get(id);
}
公共虚拟T LoadById(int-id)
{
返回会话加载(id);
}
公共虚拟列表GetAll()
{
return_session.Query().ToList();
}
公共虚拟T FirstOrDefault()
{
返回_session.Query().FirstOrDefault();
}
公共虚拟作废保存(T实体)
{
使用(ITransaction\u transaction=\u session.BeginTransaction())
{
_session.Save(实体);
_Commit();
}
}
公共虚拟作废删除(T实体)
{
使用(ITransaction\u transaction=\u session.BeginTransaction())
{
_删除(实体);
_Commit();
}
}
}

正如您已经推断的,您误解了级联的工作原理。更准确地说,NHibernate是如何工作的

对已经持久化的实体所做的所有更改都将在
Flush
上持久化


对使用同一会话检索的实体调用
session.Save()
是不可行的(我必须假设这就是您的
存储库.Save()
方法所做的,因为我没有您的源代码)

正如您已经推断的,您误解了级联的工作方式。更准确地说,NHibernate是如何工作的

对已经持久化的实体所做的所有更改都将在
Flush
上持久化


对使用同一会话检索的实体调用
session.Save()
是不可行的(我必须假设这就是您的
存储库.Save()
方法所做的,因为我没有您的源代码)

我一般不熟悉Nhibernate和数据库,所以请记住我和我的n00bish问题。在nhibernate的上下文中,你所说的禁止操作是什么意思?我已经用我的存储库类的源代码更新了我的问题。@burnt1ce调用
\u session.Save()
,对使用同一会话加载的实体执行任何操作(无操作表示无操作)。正如迭戈所说,即使您不调用
\u session.Save()
,当您调用
\u session.Flush()
(或者
\u transaction.Commit()
,如果您没有更改默认的
\u session.FlushMode
)时,更改也会写入数据库。通常,您只需对新创建的实体调用
\u session.Save()