Запрос NHibernate по экземпляру Transient приводит к исключению «сохранить экземпляр Transient» - PullRequest
1 голос
/ 12 января 2012

У меня есть старый код, который выполняет запрос, где модель может быть переходной.То есть модель с некоторыми полями, заполненными пользовательским вводом, которые затем используются как часть запроса.Он работал в NH 2.1.x, но не работает в последней версии.

Возникло исключение: «объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом».Это происходит, когда NH пытается выполнить запрос, используя непостоянный объект как часть запроса.

Упрощенная версия для иллюстрации проблемы.

abstract class BaseModel
   public virtual long Id { get; set; }

class Car : BaseModel
    public virtual Engine Engine { get;set; }

class Engine : BaseModel
    public virtual string Kind { get; set; }


public static IList<Car> GetByEngine(Engine eng) {
  ICriteria c = Session.CreateCriteria<Car>();
  c.Add(Expression.Eq("Engine", eng));
  return c.List<Car>(); // <--- Error occurs here
}

И вызывающий код эквивалентенthis:

    Engine obj = new Engine { Id = 42 }; // Transient instance
    var x = GetByEngine(obj);

То, что я ожидал (что похоже на поведение старой версии NHibernate), заключается в том, что переданный Engine используется только для получения идентификатора.То есть, генерируя SQl, как select .... from Cars, где Engine = 42

Но в новой версии NHibernate, похоже, проверяет, что двигатель, используемый в Expression, действительно сохраняется.

IsЕсть ли способ избежать необходимости загружать сохраненный движок перед выполнением запроса?

Ответы [ 3 ]

2 голосов
/ 12 января 2012

да, используя Session.Load(), который возвращает объект, если он уже находится в сеансе, или lazyLoadingProxy, если его нет.

public static IList<Car> GetByEngine(Engine eng) {
    ICriteria c = Session.CreateCriteria<Car>();
    c.Add(Expression.Eq("Engine", Session.Load<Engine>(eng.Id)));
    return c.List<Car>();
}
1 голос
/ 12 января 2012

Вы можете использовать метод Session.Load, который существует для сценариев такого типа.
Метод Load вернет объекту Proxy и не попадет в базу данных, пока вы не получите доступ к одному изэто свойства (кроме свойства Primary key, которое вообще не попадет в БД).

Использование:

Engine obj = session.Load<Engine>(42);
var x = GetByEngine(obj);

check эта статья о Session.Get и Session.Load

0 голосов
/ 13 января 2012

Я думаю, вы могли бы сделать что-то вроде этого:

public static IList<Car> GetByEngine(Engine eng) {
    ICriteria c = Session.CreateCriteria<Car>().CreateCriteria("Engine");
    c.Add(Expression.Eq("Id", eng.Id));
    return c.List<Car>();
}

В любом случае ... как возможно, что автомобиль с таким двигателем существует, если вы его еще не сохранили?

...