我有一些旧代码执行查询,其中模型可能是瞬态的。也就是说,一个模型包含一些从用户输入填充的字段,然后将其用作查询的一部分。 它在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之类的 从发动机= 42
的汽车中选择....但是新版本的NHibernate似乎检查了Expression中使用的引擎是否真的存在。
有没有办法避免在执行查询之前加载持久化引擎?
答案 0 :(得分:2)
是使用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 :(得分:1)
您可以使用Session.Load
方法,该方法适用于此类情景
Load
方法会向实体返回Proxy
,并且不会访问数据库,直到您访问其中一个属性,(Primary key
属性除外,它不会访问数据库在所有)。
用法:
Engine obj = session.Load<Engine>(42);
var x = GetByEngine(obj);
查看有关Session.Get
和Session.Load
答案 2 :(得分: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>();
}
无论如何......如果你还没有保存它,怎么可能有一台带引擎的汽车呢?