1

我有一些旧代码正在执行一个模型可以是瞬态的查询。也就是说,一个模型包含一些从用户输入中填充的字段,然后将其用作查询的一部分。它在 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
}

调用代码等价于:

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

我期望发生的事情(这似乎是旧 NHibernate 版本的行为)是传递的引擎仅用于获取 Id。也就是说,生成 SQl 之类的 select .... from Cars where Engine = 42

但是在新版本中,NHibernate 似乎会检查表达式中使用的引擎是否实际上是持久的。

有没有办法避免在执行查询之前加载持久引擎?

4

3 回答 3

2

是的,如果已经在会话中,则使用Session.Load()which 返回对象,如果不存在,则返回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>();
}
于 2012-01-12T10:57:32.730 回答
1

您可以使用Session.Load适用于此类场景的方法。
Load方法将向Proxy实体返回 a 并且在您访问其中一个Primary key属性之前不会访问数据库(除了根本不会访问数据库的属性)。

用法:

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

查看这篇关于Session.Get和的文章Session.Load

于 2012-01-12T19:57:49.533 回答
0

我认为你可以这样做:

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

无论如何...如果您还没有保存带有该引擎的汽车,它怎么可能存在?

于 2012-01-12T20:04:32.653 回答