Сохраните сирот, NHibernate один ко многим - PullRequest
0 голосов
/ 21 сентября 2011

Я успешно использую отношения один-ко-многим в NHibernate, кроме одной вещи.Когда я удаляю дочернюю запись из коллекции, хранящейся в родительской записи, я не хочу, чтобы она удаляла дочернюю запись.Я просто хочу, чтобы он исключил внешний ключ в дочерней записи.

Это позволяет позже присоединить дочернюю запись к другому родительскому элементу.

Возможно ли это?Я пробовал различные каскадные варианты, но все они, кажется, удаляют дочерний элемент, когда я вызываю Remove () для коллекции.

Вот мое родительское отображение ('SectionItem')

  <class name="Munch.Domain.MenuSection, Munch.Dao" table="menu_section">
    <id name="Id" type="Int32">
      <generator class="native" />
    </id>
    <property name="Position" />
    <property name="Title" />
    <property name="Description" />
    <bag name="MenuItems" cascade="save-update">
      <key column="menuSectionId"/>
      <one-to-many class="MenuItem"/>
    </bag>    
  </class>

Childobject (a 'MenuItem')

  <class name="Munch.Domain.MenuItem, Munch.Dao" table="menu_item">
    <id name="Id" type="Int32">
      <generator class="native" />
    </id>
    <property name="Title" />
    <property name="Description" />
    <property name="Type" />
    <property name="Image" />
  </class>

А вот тест, который создает дочернюю коллекцию и сохраняет родителя / потомков за один раз.Затем я удаляю одного дочернего элемента (записывая его идентификатор перед тем, как сделать это), а затем пытаюсь получить «удаленный» дочерний элемент, чтобы убедиться, что он все еще находится в базе данных.Я ожидаю, что он будет там, но с нулевым внешним ключом обратно к родителю.

    // Create the menu section
    MenuSection ms = new MenuSection();
    ms.Title = "MenuSectionTitle";
    ms.Description = "Description";
    ms = menuSectionDao.Save(ms);

    // Create a couple of menu items
    MenuItem item1 = new MenuItem();
    item1.Title = "AAA";
    item1.Description = "AAA Desc";

    MenuItem item2 = new MenuItem();
    item2.Title = "BBB";
    item2.Description = "BBB Desc";

    List<MenuItem> items = new List<MenuItem>();
    items.Add(item1);
    items.Add(item2);

    // Add the items to the menu section
    ms.MenuItems = items;

    // Save it and check
    menuSectionDao.Save(ms);
    Assert.IsNotNull(ms, "Menu Section wasn't saved");
    Assert.True(ms.Id > 0, "Menu Section id is not greater than zero, probably an error");

    log.Debug("MenuSection saved with id " + ms.Id);

    // See what's been saved
    MenuSection ms2 = menuSectionDao.Find(ms.Id);
    Assert.IsNotNull(ms2, "Retrieved a null value");

    // Check that the menu items were saved too
    Assert.IsNotNull(ms2.MenuItems);
    Assert.IsTrue(ms2.MenuItems.Count == 2);
    Assert.AreEqual(ms2.MenuItems[0].Title, "AAA");
    Assert.AreEqual(ms2.MenuItems[1].Title, "BBB"); 

    // Try and remove the item
    int item1Id = ms2.MenuItems[0].Id;

    log.Debug("Deleting item 0 with id " + item1Id);
    ms2.MenuItems.RemoveAt(0);
    menuSectionDao.Save(ms2);

    MenuSection ms3 = menuSectionDao.Find(ms.Id);
    Assert.IsTrue(ms3.MenuItems.Count == 1);

    // Check we haven't deleted the menu item
    MenuItem item = menuItemDao.Find(item1Id);
    Assert.IsNotNull(item);
}

(кстати, на последней строке тест не пройден)

Спасибо

Ответы [ 2 ]

1 голос
/ 21 сентября 2011

Единственная каскадная опция, которая удаляет сущности, которые удаляются из коллекции, это "all-delete-orphan".Поэтому в вашем коде должно быть что-то, что удаляет сущности.

Кроме того, убедитесь, что для родительской ссылки задано значение NULL при удалении сущности из коллекции.NHibernate не сделает этого за вас.

0 голосов
/ 22 сентября 2011

Я не очень понимаю, почему, но в итоге все заработало, так что спасибо всем, кто мне помог.

Оказывается, мне не нужно было много-к-одному в ребенке, и мне не нужно было обратное = 'true' для моего конкретного случая. Все, что мне нужно было сделать, это сохранить ребенка по отдельности (используя собственный DAO) непосредственно перед удалением его из коллекции родителей.

    IEnumerator childEnumerator = ms2.MenuItems.GetEnumerator(); 
    childEnumerator.MoveNext(); 
    MenuItem mi = (MenuItem)childEnumerator.Current; 

    menuItemDao.Save(mi);  // This is the line I needed

    ms2.MenuItems.Remove(mi); 
    menuSectionDao.Save(ms2);

Когда я сохраняю своего ребенка (миль), он все еще связан с родителем в этот момент. Я уверен, что это как-то связано с Flushing, но если кто-то может объяснить, почему это было необходимо, пожалуйста, сделайте это!

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