NHibernate устаревший государственный выпуск - PullRequest
1 голос
/ 21 ноября 2011

Мне любопытно, может кто-нибудь помочь мне решить проблему устаревшего состояния в nHibernate.

Сначала код класса .Net:

public class Test
{
    public static Test Get(int testId) { return Factory.GetTest(testId); }

    public Test() { Related = new List<TestRelate>(); }

    public virtual int ID { get; protected set; }
    public virtual string Name { get; set; }
    public virtual IList<TestRelate> Related { get; set; }

    public virtual void Delete() { Factory.Delete(this); }
    public virtual void Save() { Factory.Save(this); }

}
public class TestRelate
{
    protected TestRelate() { }
    public TestRelate(Test test) { TestID = test.ID; }
    public virtual int ID { get; protected set; }
    public virtual int TestID { get; set; }
    public virtual string Data { get; set; }

    public virtual void Delete() { Factory.Delete(this); }
    public virtual void Save() { Factory.Save(this); }
}
class Factory
{
    public static Test GetTest(int testId)
    {
        ISession session = Session.HybridSessionBuilder.Instance;
        IList<Test> ret = null;
        ITransaction tx = null;

        tx = session.BeginTransaction();
        ret = session.CreateCriteria(typeof(Test))
            .Add(Expression.Eq("ID", testId))
            .List<Test>();
        tx.Commit();

        return ret.Count == 0 ? null : ret[0];
    }
    public static void Save<T>(T element)
    {
        ISession session = Session.HybridSessionBuilder.Instance;
        ITransaction tx = null;

        tx = session.BeginTransaction();
        session.Save(element);
        tx.Commit();
    }
    public static void Delete<T>(T element)
    {
        ISession session = Session.HybridSessionBuilder.Instance;
        ITransaction tx = null;

        tx = session.BeginTransaction();
        session.Delete(element);
        tx.Commit();
    }
}

Затем XML-код отображения nHibernate:

<class name="Data.Test.Test, Data" table="test_info">
  <id name="ID" column="testid">
    <generator class="native" />
  </id>
  <property name="Name" />
  <bag name="Related" table="test_relate" lazy="false" cascade="none">
    <key column="testid"></key>
    <one-to-many class="Data.Test.TestRelate, Data"></one-to-many>
  </bag>
</class>
<class name="Data.Test.TestRelate, Data" table="test_relate">
  <id name="ID" column="relateid">
    <generator class="native" />
  </id>
  <property name="TestID" />
  <property name="Data" />
</class>

И, наконец, код, с которым у меня возникают проблемы:1009 *

Data.Test.Test Test = new Data.Test.Test();
Test.Name = "Hello World";
Test.Save();

Data.Test.TestRelate Relate = new Data.Test.TestRelate(Test);
Relate.Data = "How are you?";
Relate.Save();

Test = Data.Test.Test.Get(Test.ID);
int Count = Test.Related.Count;

Проблема в том, что список Test.Related всегда пуст, когда я запускаю этот код.Однако если я уничтожу сеанс NHibernate и снова загрузлю тест, он заполнит список, как и ожидалось.Я понимаю, что, возможно, смогу сбросить все данные кэширования, но, похоже, должно быть более чистое решение этой проблемы.Есть предложения?

Ответы [ 3 ]

1 голос
/ 21 ноября 2011

NHibernate не заполняет коллекции «один ко многим» автоматически при фиксации.Вы должны просто добавить TestRelate экземпляров в список Related, как это было бы без NHibernate, а затем (если вы установите отображение "каскадного сохранения") даже зафиксировать только экземпляр Test.

Нет необходимости использовать свойство TestID внутри программы вообще, так как это свойство фактически является только побочным продуктом реляционного отображения БД.

1 голос
/ 21 ноября 2011

Хорошо, поэтому я понял, что мой подход был из-за некоторых неудачных попыток использовать каскадирование NHibernate в прошлом.Я расскажу о каждой из проблем и о том, что я сделал для ее решения.

  1. Если я настрою каскадные сохранения, NHibernate завершится неудачно, когда я попытаюсь добавить Related элементы в новый *Элемент 1005 *, так как значение TestID не может быть нулевым в базе данных.Изменение свойства от целочисленного типа к самому типу Test исправило эту ситуацию, поскольку NHibernate смог заполнить значение поля после сохранения нового элемента Test.
  2. Попытка удалить запись Related путем ее удаления из списка приведет к ошибке из-за попытки NHibernate обновить поле TestID до нуля перед удалением.Добавление атрибута inverse="true" к элементу отображения Bag решило эту проблему.
  3. Удаление объекта Test не приведет к удалению потерянных записей Related.Установка атрибута каскада в all-orphan-delete исправила это.

Вот весь новый код (не было никаких изменений в классе Factory):

public class Test
{
    public static Test Get(int testId) { return Factory.GetTest(testId); }

    public Test() { Related = new List<TestRelate>(); }

    public virtual int ID { get; protected set; }
    public virtual string Name { get; set; }
    public virtual IList<TestRelate> Related { get; set; }

    public virtual void Delete() { Factory.Delete(this); }
    public virtual void Save() { Factory.Save(this); }
}
public class TestRelate
{
    protected TestRelate() { }
    public TestRelate(Test test) { Test = test; }
    public virtual int ID { get; protected set; }
    public virtual Test Test { get; set; }
    public virtual string Data { get; set; }

    public virtual void Delete() { Factory.Delete(this); }
    public virtual void Save() { Factory.Save(this); }
}

Отображение изменений:

<class name="Data.Test.Test, Data" table="test_info">
  <id name="ID" column="testid">
    <generator class="native" />
  </id>
  <property name="Name" />
  <bag name="Related" table="test_relate" lazy="false" cascade="all-delete-orphan" inverse="true">
    <key column="testid"></key>
    <one-to-many class="Data.Test.TestRelate, Data"></one-to-many>
  </bag>
</class>
<class name="Data.Test.TestRelate, Data" table="test_relate">
  <id name="ID" column="relateid">
    <generator class="native" />
  </id>
  <many-to-one name="Test" column="testid" />
  <property name="Data" />
</class>

Следующий код теперь работает, как и ожидалось:

Data.Test.Test Test; 
Data.Test.TestRelate Relate;

Test = new Data.Test.Test();
Test.Name = "Hello World";
Relate = new Data.Test.TestRelate(Test);
Relate.Data = "How are you?";
Test.Related.Add(Relate);
Test.Save();

Relate = new Data.Test.TestRelate(Test);
Relate.Data = "Relate #2";
Test.Related.Add(Relate);
Test.Save();

Test.Related.RemoveAt(0);
Test.Save();

Test = Data.Test.Test.Get(Test.ID);
int Count = Test.Related.Count;

Test.Delete();

Мне удалось найти большинство из этих ответов из http://ayende.com.Я настоятельно рекомендую этот сайт как ресурс для вопросов nHibernate.

1 голос
/ 21 ноября 2011

Когда вы делаете new Data.Test.TestRelate(Test), ничто не добавляет новый экземпляр TestRelate к коллекции в тесте владельца. (Если вы не сделаете это в конструкторе, но я предполагаю, что вы устанавливаете там только TestId).

Вы должны Add() новый экземпляр TestRelate для Test.Related. Nhibernate заметит изменения в коллекции и сохранит новый элемент при сбросе сеанса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...