nhibernate . Значение пакета равно нулю после создания в том же сеансе

#c# #linq #nhibernate #nhibernate-mapping

#c# #linq #nhibernate #nhibernate-сопоставление

Вопрос:

У меня есть объект, который содержит список объектов.

 public class Product: IProduct
{
    public virtual long     Id   { get; set; }
    public virtual string   Name { get; set; }

    public virtual IList<IFunction> Functions { get; set; }
}

public class Function : IFunction
{
    public virtual long     Id   { get; set; }
    public virtual string   Name { get; set; }

    public virtual IProduct Product { get; set; }
}
  

Сопоставленный список объектов ( IList < IFunction > ):

 <bag name="Functions" cascade="all" table="T_WEBFUNCTIONS" lazy="false">
  <key column="PRODUCT_ID" />
  <one-to-many class="Function" />
</bag>
  

Код :

Я пытаюсь создать новый объект продукта

     public IProduct SetProduct(string productName)
    {
         // Product repository, which have nhibernate opened session ( ISession )
         IDBRepository<IProduct> rep = Repository.Get<IProduct>();

         // Create new object of product
         rep.Create(new Product() { Name = productName });

         // get created object by name
         prod = rep.Query().Where(x => x.Name == productName).SingleOrDefault();

         // I HAVE ISSUE HERE
         // prod.Functions == NULL. It must be a new List<Function>()
         // Nhibernate don't create empty list for me and this property always null

         return prod;
    }
  

НО. Когда сеанс nhibernate закроется и откроется снова, список будет создан и будет содержать 0 элементов.

Если я создам объект (продукт) в том же сеансе и получу его после создания, bag будет иметь значение null.

Функция хранилища данных

 public class DBRepository<T> : IDBRepository<T>
{
    protected ISession CurrentSession;

    public DBRepository(ISession session)
    {
        CurrentSession = session;
    }

    public void Create(T obj)
    {
        var tmp = CurrentSession.BeginTransaction();
        CurrentSession.Save(obj);
        tmp.Commit();
    }
}
  

Ответ №1:

Когда вы вызываете new Product() , ваш код создает экземпляр объекта, и свойство List<> начинает свою жизнь как null . NHibernate не может вам здесь помочь — это то, что вы решили сделать (не переопределяя c’torпо умолчанию).

Кэш 1-го уровня NHibernate (краткое объяснение здесь) сохраняет ваш объект при фиксации транзакции, поэтому, когда в том же открытом сеансе вы запрашиваете объект по его идентификатору, NHibernate пропускает получение объекта из базы данных и предоставляет вам тот же созданный экземпляр объекта. Вы можете проверить это с Object.ReferenceEquals(prodYouCreated, prodRetrievedFromRepository) помощью .

При закрытии сеанса кэш 1-го уровня очищается, и при следующем запросе NHibernate извлекает данные и создает сам объект — он возвращает вам список нулевой длины вместо null. Это поведение по умолчанию.

Надеюсь, это поможет,
Джонно

Комментарии:

1. спасибо. это помогло. Пробовал использовать выражение rep.Create(new Product() { Name = productName, Functions = new List<IFunction>() }) . Работает хорошо

2. Не беспокойтесь. Определенно лучше пойти с Functions = new List<IFunction>() , чем с изменением c’tor’а! Мне только что пришло в голову, что «пропускает получение объекта из базы данных» в некоторых случаях верно, но не здесь. В этом случае информация уже была извлечена из базы данных (это зависит от запроса, выполненного в репозитории), поэтому сохраняется только повторное построение объекта NHibernate.