1

ベンダーと連絡先の2つのクラスがあります。ベンダーはContactの親です。ベンダーと連絡先の間には1対多の関係があります。私はベンダーと会社の間のカスケード関係をなしとして設定しました。つまり、(少なくとも私にとっては)ベンダーの連絡先を変更してベンダーを保存する場合、この保存アクションは連絡先にカスケードされないため、連絡先に加えた変更はデータベースに保持されません。

ただし、これは当てはまりません。連絡先のFirstNameを変更してその親を保存すると、保存アクションが連絡先にカスケードされます。たとえば、以下のテスト関数を使用すると、FirstName="This_new_first_name_should_not_be_saved"の連絡先が表示されます。当初、私はこの変更がデータベースに存続することを期待していませんでした。

カスケードがどのように機能するかを単に誤解しているのですか、それともコードに何か問題がありますか?

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"

        }

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>

Contact.hbm.xml

 <?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;
        }
    }

Contact.cs

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;
        }
    }

更新 * Repository.cs *

public class Repository<T> where T : class
    {
        private ISession _session;

        public Repository(ISession session)
        {
            _session = session;
        }

        public virtual T GetById(int id)
        {
            return _session.Get<T>(id);
        }

        public virtual T LoadById(int id)
        {
           return _session.Load<T>(id);
        }

        public virtual List<T> GetAll()
        {
                return _session.Query<T>().ToList();
        }

        public virtual T FirstOrDefault()
        {
            return _session.Query<T>().FirstOrDefault();
        }

        public virtual void Save(T entity)
        {
            using (ITransaction _transaction = _session.BeginTransaction())
            {
                 _session.Save(entity);
                _transaction.Commit();                
            }
        }

        public virtual void Delete(T entity)
        {
            using (ITransaction _transaction = _session.BeginTransaction())
            {
                _session.Delete(entity);
                _transaction.Commit();
            }
        }
    }
4

1 に答える 1

4

すでに推測しているように、カスケードがどのように機能するかを誤解しています。より正確には、NHibernateがどのように機能するか。

すでに永続化されているエンティティに加えたすべての変更は、に保持されFlushます。

同じセッションを使用して取得されたエンティティへの呼び出しはNO-OPです(ソースがないため、メソッドが実行session.Save()することを想定する必要があります)Repository<T>.Save()

于 2013-03-19T16:43:11.500 に答える