1

我在我的项目中使用 NHibernate & Net Persistence API 和 C# 和 MySql db,我有 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。但是说下次(任何时候,不是在同一个会话中)如果我尝试修改用户详细信息,那么它不会触发更新命令,而是触发插入,并使用修改用户实体插入一条新记录。我正在将用户的主键正确设置为修改后的对象。

此外,当我使用 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 引擎。

谁能告诉我为什么它不更新现有的用户实体?相反,它正在使用修改后的实体创建新记录?

4

2 回答 2

0

坚持永远不会触发更新。

深入研究 NH 源代码,您可能会看到在 DefaultPersistEventListener中真正实现的 Persist检查实体的状态:

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 向数据库提交插入。因此,在您进行更新的会话上下文中,所讨论的实体是瞬态的。您应该在刷新之前将此实体加载或附加到会话的上下文中。SaveOrUpdate 方法可能是一个有用的快捷方式。

于 2013-01-06T20:17:02.863 回答
0

您将实体保存在另一个 ISession 中,而不是用于检索实体的 ISession。

您能做的最好的事情是确保您使用的是相同的 ISession。我认为你真的应该考虑如何管理它。会话应该是短暂的,所以最好的办法是创建某种服务层来处理不同的用例。

于 2013-01-06T20:00:12.010 回答