Nhibernate не удалит ребенка из коллекции - PullRequest
3 голосов
/ 25 октября 2009

Первое отображение,

<set name="Comments" table="cm_events_venue_comment" inverse="true"
        lazy="true" generic="true" cascade="all-delete-orphan"
        batch-size="10" order-by="dateCreated ASC">
    <cache usage="read-write" />
    <key column="venueId" />
    <one-to-many class="VenueComment" />
</set>

Проходной тест,

[Test]
public void CanSaveAndDeleteComments()
{
    User u = TestDataHelper.CreateUser("Sir", "Talkalot");
    VenueComment comment;
    Venue v = GetVenueById();

    PerformInTransaction(() =>
    {
        userRepository.SaveOrUpdate(u);
        comment = new VenueComment()
        {
            Commenter = u,
            Text = "I like ifs and buts and i cannot lie..",
            DateCreated = DateTime.Now
        };
        v.AddComment(comment);
        comment = new VenueComment()
        {
            Commenter = u,
            Text = "And words ending in 'ly'",
            DateCreated = DateTime.Now
        };
        v.AddComment(comment);
        Assert.DoesNotThrow(()=>venueRepository.SaveOrUpdate(v));
    });

    // Test retrieval 
    Session.Evict(v);

    v = GetVenueById();
    v.Comments.Count.ShouldEqual(2);
    var c = v.Comments.FirstOrDefault<VenueComment>();
    c.Commenter.Id.ShouldEqual(u.Id);

    // and deletion
    PerformInTransaction(() =>
    {
        v.RemoveComment(c);
    });

    Session.Evict(v);
    v = GetVenueById();
    v.Comments.Count.ShouldEqual(1);

}

Мои проблемы возникают в контроллере моего приложения,

[Authenticate, AcceptAjax]
public ActionResult DeleteComment(int id)
{
    return PerformInTransaction<ActionResult>(() =>
        {
            var comment = commonDao.GetObjectById<VenueComment>(id);
            if (comment == null)
                return JsonFailure("Comment not found");

            if (comment.Commenter.Id == CurrentUser.Id ||
                AuthUtil.IsAdministrator()) //
            {

               var venue = comment.Venue;
               venue.RemoveComment(comment);

                return JsonSuccess(id);
            }
            return JsonFailure("You can only delete comments you created.");
        });
}

По данным Log4Net, удалений не было. Как я уже сказал, вышеупомянутый тест проходит, поэтому отображение должно быть правильным.

Есть какие-нибудь подсказки?

Ответы [ 3 ]

4 голосов
/ 26 октября 2009

Если вы посмотрите документацию для атрибута inverse в сопоставлениях свойств типа коллекции, вы обнаружите, что настройка inverse="false" указывает NHibernate наблюдать за родительским объектом (объектом, содержащим коллекцию) на предмет изменений в коллекции, а также для вставки / удаления дочерних объектов на основе добавления / удаления в дочерней коллекции родителя.

Но когда вы устанавливаете inverse="true", вы указываете NHibernate наблюдать за дочерним объектом на предмет изменений в ссылочном свойстве обратно к родительскому объекту. Поэтому, когда вы устанавливаете свойство родительской ссылки дочернего элемента, NHibernate затем переходит и изменяет ассоциацию.

Похоже, вы не хотите устанавливать inverse="true" в родительской коллекции родителей.

Добавление:

RemoveComment может отсоединить родителя от ребенка (как, например, установить child.Parent = null). Но если он также не отсоединяет дочерний элемент от Session, и если коллекция помечена inverse="true", что указывает на то, что ребенок владеет ассоциацией, а не коллекцией, владеющей ассоциацией, то NHibernate не будет отправлять delete , NHibernate будет отправлять delete только в том случае, если объект должен быть удален - a) если коллекции принадлежит ассоциация (inverse="false"), и каскадирование коллекции настроено на удаление, и объект удаляется из коллекции, или б) если объект удален из Session.

1 голос
/ 26 октября 2009

Тайна разгадана .... Это был случай слияния двух кодовых баз ..

У одного старого дао (commonDao) была ошибка, когда внутреннее свойство Session создавало новый сеанс из фабрики сеансов для доступа к свойству, поэтому между загрузкой объекта и flush () был другой сеанс.

Более новый код использует репозитории на основе архитектуры S # arp, которая имеет автоматическое управление сеансами, поэтому проблема не появилась в модульных тестах.

1 голос
/ 26 октября 2009

По моему опыту, это происходит, когда я забываю либо зафиксировать транзакцию, либо правильно закрыть и сбросить сеанс. Управление сеансами и транзакциями также представляет собой заметную разницу между вашим тестом и докладчиком.

...