NHibernate -延迟加载问题-初始化[]-无法初始化代理-没有会话."}

本文关键字:初始化 会话 quot 问题 延迟加载 NHibernate 代理 | 更新日期: 2023-09-27 18:09:51

你好,我使用的是Fluent NHibernate,我对延迟加载有点困惑。

  1. 我查询了数据库中的对象
  2. 修改对象属性
  3. 使用此对象更新数据库

代码如下:

public class Credentials
{
    public virtual int Id { get; set; }
    public virtual string Nick { get; set; }
    public virtual string Password { get; set; }
}
public class CredentialsMap : ClassMap<Credentials>
{
    public CredentialsMap()
    {
        Id(x => x.Id);
        Map(x => x.Nick).Column("NICK");
        Map(x => x.Password).Column("PASSWORD");
        Table("R_CREDENTAILS");
    }
}
public class Status
{
    public virtual int Id { get; set; }
    public virtual string Msg { get; set; }
    public virtual DateTime AddTime { get; set; }
}
public class StatusMap : ClassMap<Status>
{
    public StatusMap()
    {
        Id(x => x.Id);
        Map(x => x.Msg).Column("MESSAGE");
        Map(x => x.AddTime).Column("ADD_TIME");
        Table("R_STATUS");
    }
}
public class Account
{
    public virtual int Id { get; set; }
    public virtual string SelfNick { get; set; }
    public virtual Credentials Credentials { get; set; }
    public virtual Status Status { get; set; }
}
public class AccountMap : ClassMap<Account>
{
    public AccountMap()
    {
        Id(x => x.Id);
        Map(x => x.SelfNick).Column("SELF_NICK");
        References(x => x.Credentials)
            .Column("CREDENTIALS_ID")
            .ForeignKey();
        References(x => x.Status)
            .Column("STATUS_ID")
            .ForeignKey();
        Table("R_ACCOUNTS");
    }
}

NHibernate配置类

public class NHiberanteHelper
{
    private static ISessionFactory _sessionFactory;
    private static ISessionFactory SessionFactory
    {
        get
        {
            if (_sessionFactory == null)
                InitializeSessionFactory();
            return _sessionFactory;
        }
    }
    private static void InitializeSessionFactory()
    {
        _sessionFactory = Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008
                          .ConnectionString(
                               @"Server=TEST'SQLEXPRESS;Database=SimpleNHibernate;Trusted_Connection=True;").
                               ShowSql()
                              )
            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Account>().Conventions.Add( DefaultCascade.All()))
            .ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(true, true))
            .BuildSessionFactory();
    }
    public static ISession OpenSession()
    {
        return SessionFactory.OpenSession();
    }
}

用法:

    public class LoginDbHelper
    {
        public static Account GetAccount(string nick)
        {
            using (var session = NHiberanteHelper.OpenSession())
            {
                var account = (session.QueryOver<Account>()
                    .JoinQueryOver<Credentials>(a => a.Credentials)
                    .Where(c => c.Nick == nick));
                if (account != null)
                    return account.SingleOrDefault();
                return null;
            }
        }
        public static void SaveOrUpdateAccount(Account account)
        {
            using (var session = NHiberanteHelper.OpenSession())
            {
                using (var trans = session.BeginTransaction())
                {
                    session.SaveOrUpdate(account);
                    trans.Commit();
                }
            }
        }
   }
问题代码:

var actualAccount = LoginDbHelper.GetAccount(nick);
//modify
actualAccount.Status.Msg = "New status 2";
actualAccount.Status.AddTime = DateTime.Now;

LoginDbHelper.SaveOrUpdateAccount(account);

我得到这个错误:

{"Initializing[NHibernateSample1.Status#1]-Could not initialize proxy - no Session."}
异常堆栈

:

 at NHibernate.Proxy.AbstractLazyInitializer.Initialize() in d:'CSharp'NH'NH'nhibernate'src'NHibernate'Proxy'AbstractLazyInitializer.cs:line 113
   at NHibernate.Proxy.AbstractLazyInitializer.GetImplementation() in d:'CSharp'NH'NH'nhibernate'src'NHibernate'Proxy'AbstractLazyInitializer.cs:line 191
   at NHibernate.ByteCode.Castle.LazyInitializer.Intercept(IInvocation invocation) in d:'CSharp'NH'NH'nhibernate'src'NHibernate.ByteCode.Castle'LazyInitializer.cs:line 61
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.StatusProxy.set_Msg(String value)
   at NHibernateSample1.Program.Main(String[] args) in E:'C# PROJECTS'Samples'SimpleNHibernateClient'NHibernateSample1'Program.cs:line 215
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

我谷歌它,我认为这是由于延迟加载,因为在方法GetAccount我关闭SESSION。这是我第一次尝试使用NHibernate,所以如何正确解决这个问题?这是可能的禁用LAZY LOADING如果是,怎么做?

NHibernate -延迟加载问题-初始化[]-无法初始化代理-没有会话."}

你是正确的。因为NHibernate会话在你的GetAccount方法中是关闭的(它只在using语句的作用域中打开),你不能在这个方法之外加载其他对象。有两种可能的修复方法:

  1. 在操作级别创建会话(即在包含问题代码的方法中),然后在get &保存方法。您可以将会话作为参数传递给方法来使用会话。
  2. 修改对象不使用延迟加载。您可以通过在流畅映射中将.Not.LazyLoad()添加到Status对象来实现这一点。

我发现关闭延迟加载最简单的方法是添加DefaultLazy约定,即:

.Conventions.Add( DefaultCascade.All(), DefaultLazy.Never() )

请注意,启用延迟加载(DefaultLazy.Always())确实可以提高性能,具体取决于您的应用程序。

缺点是,在延迟加载实体中的其余数据之前,您总是必须打开会话。以我的经验来看,支持延迟加载的会话管理是NHibernate最大的难点之一。

在LoginDbHelper.GetAccount(…)方法中打开和关闭会话
尝试在方法外部创建和打开会话,并将其作为方法参数传递,例如:

    // method
    public static Account GetAccount(string nick, ISession session) 
    {   
     var account = (session.QueryOver<Account>().JoinQueryOver<Credentials>(a => a.Credentials).Where(c => c.Nick == nick));   
           if (account != null)                      
            return account.SingleOrDefault();                    
    return null;  
    }
// usage
    var actualAccount = LoginDbHelper.GetAccount(nick);   
    actualAccount.Status.AddTime = DateTime.Now;   
    using (var session = NHiberanteHelper.OpenSession())  
    LoginDbHelper.SaveOrUpdateAccount(account, session); 

作为一种解决方法,您可以替换以下代码:

if (account != null)
    return account.SingleOrDefault();

使用下面的代码:

if (account != null)
{
    var returnValue = account.SingleOrDefault();
    if (returnValue != null)
    {
        returnValue.Status.Msg = returnValue.Status.Msg;//Cause to load the lazy object now
    }
    return returnValue;
}

如果会话完全打开,但是调用了Session.Clear(),也可能发生这种情况。别这样。

如果您将此与ASP. net结合使用。. Net MVC或ASPCORE,问题可能是因为Json序列化器试图从IEnumerable中检索数据,您正在通过会话获得。因为序列化器是在你退出你的动作方法并且你的控制器(连同NH会话)被处理后执行的,所以它不能访问惰性加载的导航属性。

简单的解决方案是在动作方法内的LINQ查询中添加。tolist()或。toarray()。