12

无论它是否已经存在,我都需要向数据库写入一行。在使用 NHibernate 之前,这是通过存储过程完成的。该过程将尝试更新,如果没有行被修改,它将回退到插入。这很有效,因为应用程序并不关心记录是否存在。

使用 NHibernate,我发现的解决方案需要加载实体并对其进行修改,或者删除实体以便插入新实体。应用程序必须关心记录是否已经存在。有办法解决吗?

身份证重要吗?

分配的 ID

该对象有一个关键字作为分配的 id,并且是表中的主键。

我了解 SaveOrUpdate() 将根据 Id 适当调用 Save() 或 Update() 方法。使用分配的 id,这将不起作用,因为 id 不是未保存的值。但是,可以将版本或时间戳字段用作指示符。实际上,这无关紧要,因为这仅反映内存中的对象是否与数据库中的记录相关联;它不指示该记录是否存在于数据库中。

生成的 ID

如果分配的 id 确实是问题的原因,我可以使用生成的 id 而不是关键字作为主键。这将避免 NHibernate 插入/更新问题,因为它总是会有效地插入。但是,我仍然需要防止重复的关键字。使用关键字列上的唯一索引,即使主键不同,它仍然会为重复关键字抛出异常。

另一种方法?

也许问题不在于 NHibernate,而在于建模的方式。与应用程序的其他领域不同,这更以数据为中心,而不是以对象为中心。很高兴 NHibernate 使其易于读/写并消除了存储过程。但是,不考虑现有值而简单地编写的愿望与对象身份模型的模型不太吻合。有没有更好的方法来解决这个问题?

4

7 回答 7

7

我正在使用

    public IList<T> GetByExample<T>(T exampleInstance)
    {
        return _session.CreateCriteria(typeof(T))
                    .Add(Example.Create(exampleInstance))
                    .List<T>();
    }

    public void InsertOrUpdate<T>(T target)
    {
        ITransaction transaction = _session.BeginTransaction();
        try
        {
            var res=GetByExample<T>(target);
            if( res!=null && res.Count>0 )
                _session.SaveOrUpdate(target);
            else
               _session.Save(target); 
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback();
            throw;
        }
        finally
        {
            transaction.Dispose();
        }
    }

但是 FindByExample 方法返回所有对象,而不是具有确切 ID 的对象,您有什么建议?因为我只有对象作为参数我无权访问其特定的 ID 字段所以我不能使用session.get(Object.class(), id);

于 2009-01-27T08:50:27.727 回答
6

通常,NHibernate 可以依赖未保存的值来确定是否应该插入或创建实体。但是,由于您正在分配 ID,因此 NHibernate 看起来您的实体已经被持久化了。因此,您需要依靠版本控制您的对象来让 NHibernate 知道它是一个新对象。请参阅以下链接了解如何对您的实体进行版本控制:

http://web.archive.org/web/20090831032934/http://devlicio.us/blogs/mike_nichols/archive/2008/07/29/when-flushing-goes-bad-assigned-ids-in-nhibernate。 aspx

于 2009-02-04T22:17:57.210 回答
0

使用 session.SaveOrUpdate(object) 方法。

于 2008-11-28T15:17:07.363 回答
0

你可以做

Obj j = session.get(Object.class(), id);
if (j != null)
   session.merge(myObj);
else
   session.saveOrUpdate(myObj);
于 2008-11-28T16:41:38.003 回答
0

查询keyword = x的对象,取FirstOrDefault。如果为空,则添加新对象,如果存在,则更新您获得的对象并在其上调用 saveOrUpdate。

于 2018-09-27T17:31:36.837 回答
0

这对我有用:

执行

    public void InsertOrUpdate<TEntity, TId>(TEntity entity) where TEntity : IIdentificableNh<TId>
    {
        var anyy = session.Get<TEntity>(entity.Id);
        if (anyy != null)
        {
            session.Evict(anyy); //dispatch all data loaded, to allow updating 'entity' object.
            session.Update(entity);
        } 
        else
        {
            session.Save(entity);
        }
        
        session.Flush();
    }

实体

public class Caracteristica : IIdentificableNh<int>
{
    public virtual int Id { get; set; }

    public virtual string Descripcion { get; set; }
}

我必须创建一个允许我访问 Id 属性值的接口 (IIdentificableNh)。

使用示例:

session.InsertOrUpdate<Caracteristica, int>(new Caracteristica { Id = 2, Descripcion = "Caracteristica2" });
于 2021-07-29T14:40:36.737 回答
-1

调用 hibernate.saveOrUpdate() 它将检查对象是否在数据库中,如果是则更新它,如果不是则保存(即插入)它。

于 2008-11-28T15:15:48.537 回答