NHibernate不保留对我的对象的更改
我的ASP.NETMVC4项目使用NHibernate(存储库后面)和CastleWindsor,使用AutoTx和NHibernate设施。我遵循了haf和我的同事编写的指南,我可以创建和读取对象 我的PersistenceInstaller如下所示NHibernate不保留对我的对象的更改,nhibernate,asp.net-mvc-4,castle-windsor,Nhibernate,Asp.net Mvc 4,Castle Windsor,我的ASP.NETMVC4项目使用NHibernate(存储库后面)和CastleWindsor,使用AutoTx和NHibernate设施。我遵循了haf和我的同事编写的指南,我可以创建和读取对象 我的PersistenceInstaller如下所示 public class PersistenceInstaller : IWindsorInstaller { public void Install(Castle.Windsor.IWindsorContainer container,
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.AddFacility<AutoTxFacility>();
container.Register(Component.For<INHibernateInstaller>().ImplementedBy<NHibernateInstaller>().LifeStyle.Singleton);
container.AddFacility<NHibernateFacility>(
f => f.DefaultLifeStyle = DefaultSessionLifeStyleOption.SessionPerWebRequest);
}
}
最后,是导致问题的应用程序代码:
[HttpPost]
[ValidateAntiForgeryToken]
[Transaction]
public ActionResult Maintain(PrescriberMaintainViewModel viewModel)
{
if (ModelState.IsValid)
{
var prescriber = UserRepository.GetPrescriber(User.Identity.Name);
//var prescriber = new Prescriber { DateJoined = DateTime.Today, Username = "Test" };
prescriber.SecurityQuestion = viewModel.SecurityQuestion;
prescriber.SecurityAnswer = viewModel.SecurityAnswer;
prescriber.EmailAddress = viewModel.Email;
prescriber.FirstName = viewModel.FirstName;
prescriber.LastName = viewModel.LastName;
prescriber.Address = new Address
{
Address1 = viewModel.AddressLine1,
Address2 = viewModel.AddressLine2,
Address3 = viewModel.AddressLine3,
Suburb = viewModel.Suburb,
State = viewModel.State,
Postcode = viewModel.Postcode,
Country = string.Empty
};
prescriber.MobileNumber = viewModel.MobileNumber;
prescriber.PhoneNumber = viewModel.PhoneNumber;
prescriber.DateOfBirth = viewModel.DateOfBirth;
prescriber.AHPRANumber = viewModel.AhpraNumber;
prescriber.ClinicName = viewModel.ClinicName;
prescriber.ClinicWebUrl = viewModel.ClinicWebUrl;
prescriber.Qualifications = viewModel.Qualifications;
prescriber.JobTitle = viewModel.JobTitle;
UserRepository.Commit(prescriber);
}
return View(viewModel);
}
上述代码将保存一个新的处方(通过取消注释注释掉注释行等进行测试)
我正在使用NHProf,并且已经确认没有向数据库发送用于更新的sql。我可以看到正在执行读取,但仅此而已
在我看来,NHibernate不识别正在更改的实体,因此不生成sql。或者可能没有提交事务
我已经在网上搜索了几个小时,现在试图解决这个问题,作为最后的绝望行为,我已经在网上发布了。有什么想法吗?:)
哦,在NHProf中,我看到了三个会话(一个用于来自repo的GetPrescriber调用,一个用于更新(没有sql),另一个用于基类上actionfilter中的某些操作)。我还收到了关于使用隐式事务的警告。这让我很困惑,因为我认为我正在做所有我需要的事情来获得一个事务-使用AutoTx和事务属性。根据我的Windsor配置,我还希望每个webrequest只有一个会话
更新:在花了一天时间阅读NHibernateFacility的源代码和自动事务处理的AutoTx设施之后,AutoTx似乎没有在我的INHibernateInstaller实现上设置拦截器。这似乎意味着,每当SessionManager调用OpenSession时,它都会调用不带参数的默认版本,而不是接受拦截器的版本。在内部,AutoTxFacility向windsor注册TransactionInterceptor,以便windsor利用AutoTx的TransactionalComponentInspector将其添加到我的INHibernateInstaller混凝土上的拦截器中
在我看来,这就像为每次调用存储库创建会话一样。会议应涵盖整个业务运营。它应该在开始时打开,并在结束时提交和处置 这段代码中还有其他奇怪的东西
- 提交与保存或更新是完全不同的概念
- 而且你也不需要告诉NH去存储更改。您不需要调用会话。保存已在会话中的对象。无论如何,它们都是存储的。您只需在添加新对象时调用session.Save即可
- 确保在整个业务操作中使用事务
OpenSession()
会触发创建新的会话实例
protected ISession Session
{
get { return _sessionManager.OpenSession(); }
}
因此,每当代码访问Session
属性时,后面就会创建新Session实例(一次又一次)。一个会话用于get,一个会话用于udpate,一个会话用于筛选器
正如我们在这里看到的,SessionManager.OpenSession()返回的会话必须用于整个范围(工作单元、web请求…)
我们需要的Syntash,si创建一个会话(当第一次访问时),然后重用它,直到作用域的enf(然后正确关闭它、提交或回滚事务…)。无论如何,现在的第一件事是以这种方式更改会话
属性:
ISession _session;
protected ISession Session
{
get
{
if (_session == null)
{
_session = sessionFactory.OpenSession();
}
return _session;
}
}
昨天花了一整天的时间在github上的AutoTx和NHibernate设施中搜索,结果一无所获,我开始了一个干净的项目,试图复制这个问题。不幸的是,对于复制,一切都正常!我在我的源代码上运行了更新包,并下载了Castle.Transactions的新版本,运行正常。我确实对自己的代码做了一些小的调整。这是为了删除UserRepository.Commit行
我不需要修改打开会话的方式。这由SessionManager实例负责。更新到Castle.Transactions后,将识别事务属性并创建事务(NHProf中不再显示警报即可证明)。是否有错误消息?或者只是没有保留更改?没有错误消息。只是数据库中没有sql。我想我做错了什么,我只是不知道我做错了什么谢谢。我的理解是SessionManager处理会话的创建,如果当前请求中存在会话,它将被重用。因此,我只希望看到一次会议。回到Nhibernate Facility wiki条目,我看到它在上周更新了一些重要信息,这些信息是我在大约一个月前改用SessionManager时没有的。我同意提交命名,但我正在处理一个在任何地方都使用提交动词的现有抽象存储库。不管Commit具有更多的事务语义,最终结果仍然是一样的。谢谢你,当然可以。正如我在Stefans answer中所评论的,当我添加SessionManager时,NHib Facility wiki并没有这些信息(历史视图证实了这一点:)。现在我可以在wiki中看到额外的详细信息了,我知道我需要添加IsWeb标志并连接SessionWebModule-我刚刚期望的事情得到了处理,因为wiki中没有信息-而不是使用会话工厂创建会话实例。。。干杯
ISession _session;
protected ISession Session
{
get
{
if (_session == null)
{
_session = sessionFactory.OpenSession();
}
return _session;
}
}