Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ignoring methods on entity types with nHibernate

I've got a class something like this:

public class Account
{
    public virtual int Id { get; private set; }
    public virtual string Username { get; set; }

    [EditorBrowsable( EditorBrowsableState.Never )]
    public virtual string Password { get; private set; }

    public void SetPassword( string password ){ ... }
    public bool CheckPassword( string password ) { ... }
}

I've set it up this way since I don't ever want the Password property used directly in code that uses the Account type. The Account map looks something like this:

public class AccountMap : ClassMap<Account>
{
    public AccountMap()
    {
        Id( x => x.Id );
        Map( x => x.Username );
        Map( x => x.Password );
    }
}

When I actually use this with NHibernate I get an InvalidProxyTypeException

NHibernate.InvalidProxyTypeException: The following types may not be used as proxies:
    Fringine.Users.Account: method SetPassword should be virtual
    Fringine.Users.Account: method CheckPassword should be virtual

I understand that NHibernate is trying to create a proxy class to support lazy loading and that I can either mark the methods as virtual add a Not.LazyLoad() to the map to resolve the exception. But - I don't want to do either of those. I want to support lazy loading but I don't see why those methods need to be virtual.

Does NHibernate (or Castle internally) evaluate the contents of the method to determine which fields are used and optimize the lazy loading for those properties? If not, why does the method need to be virtual if all the properties are and they'll be lazy-loaded when they're referenced by the method.

Is there a way to exclude certain methods from the virtual requirement?

like image 884
Paul Alexander Avatar asked Jul 13 '09 16:07

Paul Alexander


1 Answers

The reason is that you could access fields in your methods, which will not be initialized. So the easiest way is to load the contents of the entity on any call to the object (the only exception is the access to the id, which is already available in the proxy).

So you can safely implement your methods as if there weren't proxies - with the trade-off that the method needs to be virtual (which - I agree - is not perfect).

If you think that this is a problem for your class design, try to move the functionality to another class (eg. PasswordManager, PasswordValidator etc). This class will aggregate the Account or take it it as argument, so the Account will only be loaded when this class actually calls one of its properties.

like image 89
Stefan Steinegger Avatar answered Nov 08 '22 05:11

Stefan Steinegger