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

如何使用一些初始化字段(Id除外)创建NHibernate代理对象?,nhibernate,proxy-classes,Nhibernate,Proxy Classes,我想创建一个对象代理,类似于ISession.Load返回的内容,但有些字段已初始化。对于其他属性,当访问时,代理将从数据库中获取整个对象。 考虑下面的例子: public class User { protected User() { } public User(int id, string username, string email) { // ... } // initialize the following fields

我想创建一个对象代理,类似于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; }
}
公共类用户
{
受保护用户(){
}
公共用户(int-id、字符串用户名、字符串电子邮件){
// ... 
}
//从其他数据源初始化以下字段
公共虚拟整数Id{get;set;}
公共虚拟字符串用户名{get;set;}
公共虚拟字符串电子邮件{get;set;}
//访问时,其余字段将触发数据库中的select by id
公共虚拟字符串字段1{get;set;}
公共虚拟字符串字段2{get;set;}
公共虚拟日期时间字段3{get;set;}
公共虚拟ISet注释{get;set;}
}
在我的例子中,Id、用户名和电子邮件是众所周知的,因此我可以创建一个包含这些字段的对象代理,而对于其他字段,保留默认代理行为。除了在数据库中找不到此id时引发异常外,如果预初始化字段不匹配或以静默方式覆盖它们,我还可以引发异常。我正在使用NHibernate.ByteCode.Castle作为代理工厂

编辑: 这样做的目的是能够从可以在别处查询的实体(比如lucene索引)中获得一些投影属性,并避免数据库调用。然后,我不想将这些字段包装到只包含这些属性子集的自定义组件类中,而是希望直接使用代理对象,以便在需要时加载其余字段。在最好的情况下,我根本不会访问数据库,但在某些情况下,我也希望访问其他字段。选择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 
        }
//创建初始化了某些字段的用户对象代理
var user=Session.Load(5,新的{UserName=“admin”,Email=”admin@company.com" });
Console.WriteLine(user.Id);//没有命中数据库
Console.WriteLine(user.UserName);//没有命中数据库
Console.WriteLine(user.FullName);//没有命中数据库
如果(某些条件){
Console.WriteLine(user.Field1);//获取所有其他字段
}

您可以在查询中指定一个急取,以实际检索所需的关联。根据您使用的查询样式(条件、Hql或LINQto NH),可以采用不同的方式完成。但是关键是改变获取模式。

在属性
Field1
Field2
Field3
注释
映射上指定lazy=“true”(或不指定.LazyLoad(),对于Fluent NHib)可能会有所帮助,但不能确定选择N+1问题


另一种方法是为用户名指定lazy=“false”,为非集合属性指定Email,我不会这样做
加载实体时,从数据库中预取它们的成本(通常)非常小,我甚至不会为此费心。
对于集合属性,只需将集合获取策略标记为“lazy=true”

我唯一会考虑这样做的情况是当我有大量不需要的属性时(在你的例子中,比如Field1..Field20)。
在这种情况下,我会:
1.将这些属性一起定义为,或

2.创建一个DTO,仅获取实体属性的子集。

关于大量属性,您是对的,我要查找的是实体类中字段的一个小投影(2-4个字段),但不使用别名TobeanTransformer,而是一个匿名类进行投影,因为我可以不针对数据库进行查询。在某些情况下,如果需要,还可以加载其他字段。嗯,我还没有测试过它,但是组件的想法可能会奏效。你试过了吗?问题是,一旦加载组件的一个属性,所有其他属性也将加载。