NHibernate 通过 Transient 实例查询导致“保存瞬态实例”异常

发布于 2024-12-26 09:45:08 字数 973 浏览 0 评论 0原文

我有一些旧代码正在执行查询,其中模型可能是瞬态的。也就是说,模型中的一些字段由用户输入填充,然后用作查询的一部分。 它在 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 版本的行为)是传递的 Engine 仅用于获取 Id。也就是说,生成SQl就像 select .... from Cars where Engine = 42

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

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

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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

命比纸薄 2025-01-02 09:45:08

是的,使用 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>();
}

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>();
}
溺渁∝ 2025-01-02 09:45:08

您可以使用针对此类场景的 Session.Load 方法。
Load 方法将向实体返回一个Proxy,并且在您访问其属性之一之前不会访问数据库(主键除外) code> 属性根本不会影响数据库)。

用法:

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

检查这个 关于 Session.GetSession.Load 的文章

You can use the Session.Load method, which exist for this kind of scenarios.
The Load method will return a Proxy to the Entity and won't hit the Data Base untill you access one of it's properties, (except the Primary key property which won't hit the DB at all).

Usage:

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

check this article about Session.Get and Session.Load

网白 2025-01-02 09:45:08

我认为你可以做这样的事情:

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

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

I think you could do something like this:

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

Anyway... how it's possible that a car with that engine exists if you haven't saved it yet?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文