Search code examples
nhibernatetransient

NHibernate query by Transient instance results in "save the transient instance"-exception


I have some old code which is performing a query where a model can be transient. That is, a model with some fields populated from user input, which are then used as part of the query. It worked under NH 2.1.x, but is failing under the latest version.

The exception raised is "object references an unsaved transient instance - save the transient instance before flushing". This happens when NH attempts to perform a query using a non-persisted object as part of the query.

A simplified version to illustrate the problem.

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
}

And calling code is equivalent to this:

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

What I expected to happen (Which appears to be the behaviour of the old NHibernate version), is that the Engine passed is used only for getting the Id. That is, generating SQl like select .... from Cars where Engine = 42

But with the new version NHibernate seems to check that the engine used in the Expression is actually persisted.

Is there a way to avoid having to load a persisted Engine before performing the query ?


Solution

  • yes using Session.Load() which returns the object if already in the session or a lazyLoadingProxy if not present.

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