您好我使用Fluent NHibernate,我对Lazy Loading感到困惑。
这是代码:
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怎么办?
答案 0 :(得分:8)
你是对的。因为NHibernate会话在GetAccount方法中关闭(它只在using
语句的范围内打开),所以不能在此方法之外加载其他对象。有两个可能的修复:
.Not.LazyLoad()
添加到流畅映射中的Status
对象来执行此操作。答案 1 :(得分:4)
我发现关闭延迟加载的最简单方法是添加DefaultLazy约定,即:
.Conventions.Add( DefaultCascade.All(), DefaultLazy.Never() )
请注意,启用延迟加载(DefaultLazy.Always())可以真正提高性能,具体取决于您的应用程序。
缺点是,在您可以延迟加载实体中的其余数据之前,您必须打开会话。根据我的经验,支持延迟加载的会话管理是NHibernate的一大难点。
答案 2 :(得分:0)
您可以在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);
答案 3 :(得分:0)
作为解决方法,您可以替换以下代码:
$ awk -F";" ' /^cell/ { print ; next } { a=$1; getline; print $1, a ";" } ' nehac.txt
cell1
input C;
input Cp;
input D;
output Q;
output Qn;
cell2
input Cp;
input D;
output Q;
cell3
input A1;
input B;
input B1;
output S;
output Sn;
$
使用以下代码:
if (account != null)
return account.SingleOrDefault();
答案 4 :(得分:0)
如果您的会话完全打开但您调用了 Session.Clear()
,也会发生这种情况。不要那样做。