【问题标题】:NHibernate Session/Transaction WoesNHibernate 会话/事务问题
【发布时间】:2012-03-30 02:04:15
【问题描述】:

我正在尝试使用每个请求会话模式,但在保存记录后我无法立即获取记录。这样做的原因是我需要获取与外键相关的记录。

一些(简化的)代码:

    // UnitOfWork Attribute

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        SessionFactory.Begin();
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        if (filterContext.Exception == null) {
            try {
                SessionFactory.Commit();
            } catch {
                SessionFactory.Rollback();
                throw;
            }
        } else {
            SessionFactory.Rollback();
            throw filterContext.Exception;
        }
    }

    // Service layer

    public void Save(Form form)
    {
        _repository.Save(form);

        var savedForm = _repository.Get(form.Id);
        SendEmail(savedForm);
    }

    // Repository

    public void Save(Form form)
    {
        var session = SessionFactory.CurrentSession;

        session.SaveOrUpdate(form);
    }

问题是当我尝试获取记录时,事务还没有提交,所以它只是给了我会话中已经存在的内容。我是不是只需要在保存后提交事务,然后打开一个新事务来获取它?

谢谢

更新:

我已经实现了 Agathas Storefront 的做事方式,让服务层控制事务,即:

public class UnitOfWork : IUnitOfWork
{
    public void Commit()
    {
        var session = SessionFactory.CurrentSession;

        using (ITransaction transaction = session.BeginTransaction())
        {
            try { 
                transaction.Commit(); 
            } catch {
                transaction.Rollback();
                throw;
            }
        }
    }


    public void Clear()
    {
        var session = SessionFactory.CurrentSession;

        session.Clear();
    }
}

然后在服务层:

public void SaveForm(Form form)
{
    _repository.Save(form);

    _uow.Commit();
    _uow.Clear();

    var savedForm = _repository.Get(form.Id);
    SendEmail(savedForm);
}

更新 2

好的,我想我找到了合适的解决方案。我已经回到了每请求事务模式,在保存表单后,我现在刷新它,然后从会话中驱逐表单,以强制 NH 从数据库中获取它。

// Service layer
public void SaveForm(Form form)
{
    _repository.Save(form);

    var savedForm = _repository.Get(form.Id);
    SendEmail(savedForm);
}

// Repository

public void Save(Form form)
{
    var session = SessionFactory.CurrentSession;

    session.SaveOrUpdate(form);
    session.Flush();
    session.Evict(form);
}

【问题讨论】:

  • 你是列ID的标识列吗?
  • 我是,但这并不是我的主要问题(尽管它仍然是一个问题)。我的主要问题是无法加载外键记录。也许延迟加载可以解决这个问题?
  • 这是你的问题,身份是你的敌人,尤其是当你使用工作单元时。如果没有先发送到数据库,实体如何获取其 ID?
  • 我明白你在说什么,但是正如我对Fourth 所说的,这是一个我正在转换为NH 的项目,所以现在改变我生成ID 的方式不是一个好主意。无论如何,我已经发布了第二个更新来解决这个问题。
  • 我并不是说你应该改变,我也没有说过你应该改变,我只是说身份对于 uow 实现来说不是那么好。

标签: nhibernate session transactions


【解决方案1】:

在您刷新会话或缩小事务范围之前,您不会有 ID,因为 nhibernate 不会插入记录。

【讨论】:

  • 谢谢。 session.Refresh() 似乎没有用,尽管 session.Clear() 可以。我最终稍微改变了工作单元模式,让服务层控制事务而不是每个请求都有一个事务,就像 Agathas Storefront 项目一样。
  • 如果您自己分配 ID,您可以为每个请求进行事务处理(hilo 或 guid 对此很好,已经有算法)。
  • 问题是这是一个我现在正在转换为 NHibernate 的项目,所以我真的不想开始搞乱数据库中已经存在的 ID。
  • 是的,那会很粗糙。我同意这不是一个好主意。
  • 我仍然对使用上面发布的 Agathas Storefront 示例不太满意,但我想现在必须这样做。在 NHibernate 中管理会话/事务的方法似乎有很多,我仍然没有找到理想的解决方案。
【解决方案2】:

一个选项,将您的 id 策略从数据库中生成的身份更改为由 NHibernate 管理的身份(请参阅http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-id-generator 的选项)或另一个选项将您的 Session 的刷新模式更改为 FlushMode.Auto。

【讨论】:

  • 感谢您的建议,但我宁愿坚持使用数据库中生成的身份。
猜你喜欢
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多