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

时间:2011-06-14 12:42:47

标签: nhibernate proxy-classes

我想创建一个对象代理,类似于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 = "admin@company.com" });
        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 
        }

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

想要做类似事情的唯一情况是,当我拥有大量不需要的属性时(在你的例子中,比如Field1..Field20)。
在那种情况下,我会: 1.将这些属性一起定义为component
2.创建DTO以仅获取实体属性的子集。

答案 2 :(得分:-1)

在属性Field1上指定lazy =“true”(或Fluent NHib的Not.LazyLoad()),Field2Field3Comments映射可能会有所帮助,不确定选择N + 1问题。

另一种方法是为UserName指定lazy =“false”,Email