NHibernate - 非唯一对象异常

NHibernate - NonUniqueObjectException

TL;DR 版本是这样的:尝试在单元测试中删除实体时,我不断收到 NonUniqueObjectException。如果 NHibernate 不使用 Equals 方法或 GetHashCode,谁能告诉我它如何检查缓存和比较对象?

我有一个应用程序正在尝试使用以下代码进行测试。

[Test]
public void _04_Category_Delete_Test() {
   using(var lifetime = container.BeginLifetimeScope()) {
       ICategoryRepository categoryRepository = lifetime.Resolve<ICategoryRepository>();
       DefaultCommandBus commandBus = lifetime.Resolve<DefaultCommandBus>();
       IMappingEngine mapper = lifetime.Resolve<IMappingEngine>();

       Category category = categoryRepository.Get(x => x.Title == "Category Descriptions Blah blah");
       Assert.IsNotNull(category, "Error: Category was not found.");

       DeleteCategoryCommand command = mapper.Map<DeleteCategoryCommand>(category);

       ICommandHandler<DeleteCategoryCommand> commandHandler = lifetime.Resolve<ICommandHandler<DeleteCategoryCommand>>();
       ICommandResult result = commandBus.Submit(command, commandHandler);

       Assert.IsNotNull(result, "Error: Category was not deleted by command bus");
       Assert.IsTrue(result.Success, "Error: Category was not deleted by command bus.");
   }
}

如您所见,类别实体映射到命令对象并通过命令总线传递给处理程序。在处理程序中,命令对象随后被转换回实体。此转换的映射配置文件忽略除 Id 之外的所有属性。

删除的通用存储库是:

    public bool Delete(T entity) {
        this.session.Delete(entity);
        return true;
    }

执行此方法时,我得到一个 NonUniqueObjectException。我有一个通用的 EntityBase,我的实体从中继承,并覆盖 Equals 和 GetHashCode 方法。在调试器中,我可以测试传递给 Delete 方法的实体与 NHibernate 会话缓存中的实体是否相等,并且它们的计算结果为真。当 Delete 方法在会话对象上执行时,它不会执行任何重写的 Equals 或 GetHashCode 方法。

如果 NHibernate 不使用 Equals 方法或 GetHashCode,谁能告诉我它如何检查缓存和比较对象?我修改了我的代码如下,但感觉像 hack。

    public bool Delete(T entity) {
        var id = entity.GetType().GetProperty("Id").GetValue(entity, null);
        var sessionEntity = this.session.Load<T>(id);

        var sessionEntityHashCode = sessionEntity.GetHashCode();
        var entityHashCode = entity.GetHashCode();

        if (!ReferenceEquals(null, sessionEntity)) {
            this.session.Delete(sessionEntity);
        } else {
            this.session.Delete(entity);
        }

        return true;
    }

事实证明这是一个范围界定问题。我不得不将代码更改为以下内容:

Category category = null; 

using(var lifetime = container.BeginLifetimeScope()) {
    ICategoryRepository categoryRepository = lifetime.Resolve<ICategoryRepository>();
    DefaultCommandBus commandBus = lifetime.Resolve<DefaultCommandBus>();
    IMappingEngine mapper = lifetime.Resolve<IMappingEngine>();

    category = categoryRepository.Get(x => x.Title == "Updated Category Title");
    Assert.IsNotNull(category, "Error: Category was not found.");
}

using(var lifetime = container.BeginLifetimeScope()) {
    DefaultCommandBus commandBus = lifetime.Resolve<DefaultCommandBus>();
    IMappingEngine mapper = lifetime.Resolve<IMappingEngine>();

    DeleteCategoryCommand command = mapper.Map<DeleteCategoryCommand>(category);

    ICommandHandler<DeleteCategoryCommand> commandHandler = lifetime.Resolve<ICommandHandler<DeleteCategoryCommand>>();
    ICommandResult result = commandBus.Submit(command, commandHandler);

    Assert.IsNotNull(result, "Error: Category was not deleted by command bus");
    Assert.IsTrue(result.Success, "Error: Category was not deleted by command bus.");
}