开发者

How to create a NHibernate proxy object with some initiliazed fields (other than Id)?

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 开发者_StackOverflow社区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 = "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 
        }


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.


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.


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜