C # - NHibernate: выселить сущность, а затем получить ее - PullRequest
0 голосов
/ 28 сентября 2018

Я пытаюсь понять, как работает NHibernate.Для этого я создал небольшой тест, приведенный ниже.Но на отмеченной строке тест не пройден, и я не понимаю, почему.

Что я неправильно понимаю?

Чтобы кратко объяснить фрагмент кода ... Я создаю сущность в БД,Затем я вызываю Evict, чтобы удалить объект из кэша сеанса, чтобы следующий вызов вызвал чтение БД.Затем я выполняю чтение БД, но вместо того, чтобы вернуть экземпляр сущности, прочитанный из БД, я получаю NULL в отмеченной строке.

using NHibernate;
using MyCorp.MyProject.Resources.MyEntity;
using MyCorp.MyProjectTests.Common.Fixture;
using Xunit;

namespace MyCorp.MyProjectTests.Common.DB
{
    [Collection("Component")]
    public class NHibernateTest
    {
        private readonly ISessionFactory dbSessionFactory;

        public NHibernateTest(ComponentFixture componentFixture)
        {
            this.dbSessionFactory = componentFixture.DatabaseFixture.DBSessionFactory;
        }

        [Fact]
        [Trait("Category", "Component")]
        public void TestSessionCache()
        {
            const string QUERY = @"DELETE MyEntityModel mg WHERE mg.Id = :id";
            const string TITLE = "NHibernate session test object";

            using (ISession dbSession = this.dbSessionFactory.OpenSession())
            {
                // Create new entity and then remove it from session cache.
                long id = (long) dbSession.Save(new MyEntityModel
                {
                    Title = TITLE
                });
                dbSession.Evict(dbSession.Get<MyEntityModel>(id));

                // Entity loaded from DB and stored into session cache.
                Assert.Equal(TITLE, dbSession.Get<MyEntityModel>(id).Title); // ===== FAILS HERE =====

                // Delete entity from DB, but don't evict from session cache yet.
                dbSession.CreateQuery(QUERY).SetParameter("id", id).ExecuteUpdate();

                // Entity still reachable through session cache.
                Assert.Equal(TITLE, dbSession.Get<MyEntityModel>(id).Title);

                // Evict deleted entity from session cache.
                dbSession.Evict(dbSession.Get<MyEntityModel>(id));

                // Entity not available in neither DB nor session cache.
                Assert.Null(dbSession.Get<MyEntityModel>(id));
            }
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

Ответ от @OskarBerggren объясняет работу метода Save().Я отвечаю с точки зрения UoW.

С ORM, как NHibernate, вы лучше поймете Единица работы , прежде чем использовать ее вживую.Именно в этом и заключается проблема.

UoW отслеживает действия «что делать» в заданной области действия UoW.Таким образом, когда вы звоните Save():

  1. UoW (ISession в случае NHibernate) отмечает, что эта сущность должна быть вставлена ​​ последняя в некоторой точке .
  2. Добавляет сущность в кэш сеанса.

По поводу пункта 1 выше, «последний в некоторой точке» определяется как FlushMode.Он может быть вставлен не сразу, в зависимости от установленного режима очистки.

Чтобы сделать ваш тест работоспособным, вы можете либо установить FlushMode на MANUAL и позвонить Flush() после Save().Или вы можете установить его на ALWAYS.Пожалуйста, ознакомьтесь со связанной документацией, прежде чем применять это.Режим промывки следует выбирать осторожно.

Ваш код не подходит для UoW.Я обычно устанавливаю режим сброса на COMMIT, который лучше всего использует UoW с NHibernate.UoW сбрасывается (все изменения сохраняются) в конце области.

public sealed class DbSession : IDbSession
{
    public DbSession()
    {
        session = sessionFactory.OpenSession();
        transaction = session.BeginTransaction();
    }

    ISession session = null;
    ITransaction transaction = null;

    /*
     * By default, the instance should be dirty.
     * Caller should explicitly set the property to 'false' in calling code if everything was fine.
     * If caller fail to set this property, it will be assumed that caller do not want to flush
     * the changes to database.
    */
    bool isDirty = true;
    bool IDbSession.IsDirty { set { isDirty = value; } }

    public void Dispose()
    {
        if(session == null)
            return;

        if(isDirty == false)
            transaction.Commit();
        else
            transaction.Rollback();
        transaction.Dispose();
        transaction = null;

        session.Dispose();
        session = null;
    }
}
0 голосов
/ 29 сентября 2018

Save () не равно SQL INSERT.

Save () означает: сделать сеанс осведомленным об этом объекте и разрешить сеансу отправить его в базу данных в подходящее время ,В зависимости от отображений и конфигурации, это может быть до возврата Save () или нет.

Таким образом, вы исключаете объект из сеанса до его сохранения.

ЕслиВы пропускаете вызов Evict (), ваш тест работает, потому что никакой другой код на самом деле не зависит от элемента в базе данных (оператор DELETE может указывать, что он нашел 0 строк для удаления, но это не проблема для теста).

Чтобы использовать режим автоматического сброса, вы всегда должны быть внутри транзакции, а не просто сеанса.На самом деле, для лучшей надежности вы всегда должны быть внутри транзакции, когда вы находитесь внутри сеанса (возможны другие шаблоны, но, как правило, их сложнее понять).

Вот документация о том, когдапроисходит сброс изменений в базу данных: http://nhibernate.info/doc/nhibernate-reference/manipulatingdata.html#manipulatingdata-flushing

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...