NHibernate在修改现有实体时不触发update语句
本文关键字:update 语句 实体 修改 NHibernate | 更新日期: 2023-09-27 17:50:53
我正在使用NHibernate &Net持久性API与c#和MySql数据库在我的项目中,我有UI层(ASP.NET),业务层和数据访问层(DAL)。我在DAL的UserManager类中有以下保存方法:
private EntityManager GetEm()
{
if (_entityManager == null)
{
_entityManagerFactory = Persistence.CreateEntityManagerFactory("JPUMain");
_entityManager = _entityManagerFactory.CreateEntityManager();
}
return _entityManager;
}
public void **Save**(IGenericEntity entity)
{
_entityManager = GetEm();
_entityManager.GetTransaction().Begin();
_entityManager.Persist(entity);
_entityManager.Flush();
_entityManager.GetTransaction().Commit();
_entityManager.Clear();
}
我的用户实体:
[Entity]
[Table(Name = "user")]
public class User : IGenericEntity
{
[Id]
[GeneratedValue]
public virtual int ID { get; set; }
[Basic]
[Column(Name = "fname", Nullable = false)]
public virtual string FirstName { get; set; }
[Basic]
[Column(Name = "lname", Nullable = false)]
public virtual string LastName { get; set;
}
现在如果我想通过调用
来保存用户UserManager.save(user)
则它将条目正确地保存到db。但是,假设下一次(任何时候,不是在同一会话中),如果我尝试修改用户详细信息,那么它将触发insert而不是update命令,并使用modify user实体插入一条新记录。我将user的主键正确地设置为已修改的对象。
同样,当我使用NUnit运行相同的测试用例时,它打印以下行:
NHibernate: SELECT LAST_INSERT_ID()
NHibernate: INSERT INTO user (uid, fname, lname) VALUES (?p0, ?p1, ?p2);?p0 = 2[Type: Int32 (0)], ?p1 = 'First Name' [Type: String (9)], ?p2 = 'Last Name' [Type: String (9)]
我尝试直接从phpmyadmin在用户表中运行这条语句,它总是给出0值。我使用的是InnoDB引擎
谁能告诉我为什么它不更新现有的用户实体?而是用修改后的实体创建一个新记录?
您将实体保存在另一个issession中,而不是用于检索实体的issession。
你能做的最好的事情是确保你使用相同的session。我觉得你应该好好想想怎么处理这件事。会话应该是短暂的,所以最好的方法是创建某种服务层来处理不同的用例。
持久化从不触发更新。
深入NH源代码,你可能会看到持久化,它实际上是在DefaultPersistEventListener中实现的,检查实体的状态:
public class DefaultPersistEventListener : AbstractSaveEventListener, IPersistEventListener
{
//..
public virtual void OnPersist(PersistEvent @event, IDictionary createdAlready)
{
//...
EntityState entityState = GetEntityState(entity, @event.EntityName, source.PersistenceContext.GetEntry(entity), source);
switch (entityState)
{
case EntityState.Persistent:
EntityIsPersistent(@event, createdAlready);
break;
case EntityState.Transient:
EntityIsTransient(@event, createdAlready);
break;
case EntityState.Detached:
throw new PersistentObjectException("detached entity passed to persist: " + GetLoggableName(@event.EntityName, entity));
default:
throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
}
}
唯一方法EntityIsTransient向DB提交插入。在会话的上下文中,你正在做更新,有问题的实体是暂时的。在刷新之前,应将此实体加载或附加到会话的上下文中。SaveOrUpdate方法可能是一个有用的快捷方式。