如何创建带有一些初始化字段(Id 除外)的 NHibernate 代理对象?

发布于 2024-11-15 06:13:23 字数 1751 浏览 5 评论 0原文

我想创建一个对象代理,类似于 ISession.Load 返回的内容,但初始化了一些字段。对于其他属性,当访问时,代理将从数据库中获取整个对象。 考虑以下示例:

public class User
{
    protected User() {

    }

    public User(int id, string username, string email) {
        // ... 
    }

    // initialize the following fields from other datasources
    public virtual int Id { get; set; }
    public virtual string UserName { get; set; }
    public virtual string Email { get; set; }

    // the rest of fields when accessed will trigger a select by id in the database
    public virtual string Field1 { get; set; }
    public virtual string Field2 { get; set; }
    public virtual DateTime Field3 { get; set; }
    public virtual ISet<Comment> Comments { get; set; }
}

在我的例子中,Id、UserName、Email 是众所周知的,因此我可以创建一个包含这些字段的对象代理,而对于其他字段则保留默认代理行为。除了在数据库中找不到此 id 时抛出异常之外,如果预初始化字段不匹配或静默覆盖它们,我还可以抛出异常。我正在使用 NHibernate.ByteCode.Castle 作为代理工厂。

编辑: 这样做的目的是能够从实体中获得一些投影属性,这些属性可以在其他地方查询(例如 lucene 索引)并避免数据库调用。然后,我不想将这些字段包装在仅包含这些属性子集的自定义组件类中,而是直接使用代理对象,以便能够在需要时加载其余字段。在最好的情况下,我根本不会访问数据库,但在某些极端情况下,我也想访问其他字段。通过使用批处理可以大大减少 SELECT N+1 问题的影响。 我想使用的代码的假设版本是:

        // create User object proxy with some fields initialized
        var user = Session.Load<User>(5, new { UserName = "admin", Email = "[email protected]" });
        Console.WriteLine(user.Id); // doesn't hit the database
        Console.WriteLine(user.UserName); // doesn't hit the database
        Console.WriteLine(user.FullName); // doesn't hit the database
        if (somecondition) {
            Console.WriteLine(user.Field1); // fetches all other fields 
        }

I want to create an object proxy, similar to what ISession.Load is returning, but with some fields initialized. For other properties, when accessed, the proxy will fetch the entire object from database.
Consider the following example:

public class User
{
    protected User() {

    }

    public User(int id, string username, string email) {
        // ... 
    }

    // initialize the following fields from other datasources
    public virtual int Id { get; set; }
    public virtual string UserName { get; set; }
    public virtual string Email { get; set; }

    // the rest of fields when accessed will trigger a select by id in the database
    public virtual string Field1 { get; set; }
    public virtual string Field2 { get; set; }
    public virtual DateTime Field3 { get; set; }
    public virtual ISet<Comment> Comments { get; set; }
}

The Id, UserName, Email are well-known in my case, so I could create an object proxy containing these fields, and for the others leave the default proxy behavior. In addition to throwing an exception if this id is not found in the database, i could throw an exception if preinitialized fields do not match or overwrite them silently. I am using NHibernate.ByteCode.Castle for proxy factories.

Edit:
The purpose for this is to be able to have some projection properties from an entity which can be queried elsewhere (say. a lucene index) and to avoid database calls. Then instead of wrapping these fields in a custom component class containing only these subset of properties, I want to use the proxy object directly so that I am able to load the rest of fields if needed. In the best case scenario I wouldn't hit the database at all, but in some corner cases I'd like to access other fields, too. The SELECT N+1 problem's impact can be greatly reduced by using batching.
An hypothetical version of code I want to use would be:

        // create User object proxy with some fields initialized
        var user = Session.Load<User>(5, new { UserName = "admin", Email = "[email protected]" });
        Console.WriteLine(user.Id); // doesn't hit the database
        Console.WriteLine(user.UserName); // doesn't hit the database
        Console.WriteLine(user.FullName); // doesn't hit the database
        if (somecondition) {
            Console.WriteLine(user.Field1); // fetches all other fields 
        }

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

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

发布评论

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

评论(3

半世蒼涼 2024-11-22 06:13:23

您可以在查询中指定急切获取以实际检索所需的关联。这可以通过不同的方式完成,具体取决于您使用的查询样式( Criteria、Hql 或 LINQto NH )。但关键是改变获取模式。

You can specify an eager fetch inside the query to actually retrieve the needed associations. This could be done in different ways depending on what query style ( Criteria,Hql or LINQto NH ) you are using. But the key is changing the fetch mode.

你在我安 2024-11-22 06:13:23

对于非集合属性,我不会这样做;
当您加载实体时从数据库预取它们的成本(通常)非常小,我什至不会打扰。
对于集合属性,只需将集合获取策略标记为'lazy=true'

考虑做类似事情的唯一情况是当我有大量不需要的属性时(在您的示例中 - 比如说 Field1..Field20)。
在这种情况下,我会:
1. 将这些属性一起定义为组件 ,或
2. 创建一个 DTO 以仅获取实体属性的子集。

for non-collection properties, I wouldn't do that;
the cost of prefetching them from the DB when you load your entity is (usually) so small that I wouldn't even bother.
for collection properties, just mark the collection fetch strategy as 'lazy=true'.

The only case where I would think about doing something like that is when I have a very large number of properties which I don't need (in your example- say Field1..Field20).
In that case I would either:
1. Define those properties together as a component, or
2. create a DTO for fetching only a subset of your entity's properties.

疧_╮線 2024-11-22 06:13:23

在属性 Field1Field2Field3Comments 上指定lazy = "true"(对于 Fluent NHib 则为 Not.LazyLoad()) 映射可能会有所帮助,但不确定 Select N+1 问题。

另一种方法是为UserNameEmail指定lazy = "false"

specifying lazy = "true" (or Not.LazyLoad() for Fluent NHib) on properties Field1, Field2, Field3, Comments mappings may help, though not sure about Select N+1 issue.

another way to go is specifying lazy = "false" for UserName, Email

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