使用nHibernate忽略实体类型的方法

时间:2009-07-13 16:30:07

标签: c# fluent-nhibernate

我有一个这样的课:

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 ) { ... }
}

我已经这样设置了,因为我不希望在使用Password类型的代码中直接使用Account属性。帐户地图如下所示:

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

当我在NHibernate中实际使用它时,我得到一个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

据我所知,NHibernate正在尝试创建一个支持延迟加载的代理类,并且我可以将这些方法标记为虚拟,将Not.LazyLoad()添加到地图中以解决异常。但是 - 我不想做其中任何一个。我想支持延迟加载,但我不明白为什么这些方法需要是虚拟的。

NHibernate(或内部Castle)是否评估方法的内容以确定使用哪些字段并优化这些属性的延迟加载?如果没有,为什么该方法需要是虚拟的,如果所有属性都是,并且当它们被方法引用时它们将被延迟加载。

有没有办法从虚拟要求中排除某些方法?

3 个答案:

答案 0 :(得分:7)

原因是您可以访问方法中的字段,这些字段不会被初始化。因此,最简单的方法是在对对象的任何调用中加载实体的内容(唯一的例外是对代理中已有的id的访问)。

因此,您可以安全地实现您的方法,就好像没有代理一样 - 权衡该方法需要是虚拟的(我同意 - 这并不完美)。

如果您认为这是您的类设计的问题,请尝试将该功能移至另一个类(例如PasswordManager,PasswordValidator等)。此类将聚合Account或将其作为参数,因此只有在此类实际调用其中一个属性时才会加载Account。

答案 1 :(得分:0)

我注意到NHibernate在很大程度上依赖于所有实体的POCO。无论好坏,我都没有遇到任何有人违反惯例的情况。 Davy Brion explains it in great detail here. (他引用了你的观点,是的,你可以将类标记为非延迟加载。但是,因为nHibernate不会创建任何代理,所以你被卡住了。)

我不知道这是否有用,但Castle就是这样做的。现在(如果您使用的是2.1)you're able to choose which proxy generator to use,移至one of the other choices可能允许您以适合您需要的方式生成代理。

答案 2 :(得分:0)

您可以在类级别停用延迟加载并在属性的基础上激活它,延迟加载通常用于集合关联关系。

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

或者您可以尝试使用私有字段和“字段”策略:

public class AccountMap : ClassMap<Account>{        
    public AccountMap()
    {

        Id( x => x.Id );
        Map( x => x.Username )
        Map( x => x.Password).Access.AsCamelCaseField();         
    }
}

public class AccountMap : ClassMap<Account>{        
   private string password;
   public string Password{ get; }
}