Spring / Hibernate заменяет набор каскадных объектов - PullRequest
0 голосов
/ 22 декабря 2011

Обновление: я переписал вопрос, чтобы сделать его максимально понятным и предоставить больше информации.

У меня есть следующее:

@Entity
public class FooLnkBar implements java.io.Serializable {
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "SomeID", nullable = false)
    private Foo foo;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "OtherID", nullable = false)
    private Bar bar;
}

@Entity
public class Foo implements java.io.Serializable {
    @OneToMany(orphanRemoval=true, cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "foo")
    private Set<FooLnkBar> fooLnkBars = new HashSet<FooLnkBar>(0);
}

Случай 1: Сохраните все, сохранив FooLnkBar

 // This correctly saves everything into the database in one shot
 Foo foo = new Foo();
 Bar bar = new Bar();
 FooLnkBar flb = new FooLnkBar();
 flb.setFoo(foo);
 flb.setBar(bar);
 persist(flb);

Случай 2: Изменить FooLnkBar и сохранить Foo

 // Load a Foo from the database and get the set of FooLnkBars
 Foo foo = loadFooFromDatabase();
 Set<FooLnkBar> fooLnkBars = foo.getFooLnkBars();

 // Delete all existing FooLnkBar objects. Alternatively use removeAll()
 Iterator<FooLnkBar> it = fooLnkBars.iterator();
 while (it.hasNext()) {
   FooLnkBar o = it.next();
   it.remove();
 }

 // Add some new FooLnkBars
 Foo foo = new Foo();
 Bar bar = new Bar();
 FooLnkBar flb = new FooLnkBar();
 fooLnkBars.add(flb);
 foo.setFooLnkBars(fooLnkBars);

 // Save all changes
 persist(foo);

Случай 2 не работает.Из-за cascadeType это также удаляет Foo, в котором находится FooLnkBar, поэтому весь объект Foo в случае 2 удаляется.Это плохо.

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

Если яудалить Foo из базы данных, FooLnkBar также должен быть удален из базы данных.

Если я удаляю FooLnkBar из базы данных, Foo НЕ следует удалять из базы данных.

Я ищу способ, чтобы все дела работали.

Обновление: при изменении этого исправления Случай 2, но с ошибками Случай 1:

   @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
   @JoinColumn(name = "SomeID", nullable = false)
   private Foo foo;

Сообщение об ошибке в случае 1 теперь "свойство not-null указывает на нулевое или временное значение: FooLnkBar.foo"

Ответы [ 2 ]

2 голосов
/ 22 декабря 2011

Кажется, он делает именно то, что вы сказали:

ObjectOne obj1 = findInDatabase ();

Загрузка постоянного объекта.

obj1.addSet (objTwoSet);

Добавление содержимого набора к существующему набору объекта (таким образом, «объединяя» два набора).

sessionFactory.getCurrentSession () saveOrUpdate (obj1);.

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

Чтобы очистить существующее содержимое набора и добавить весь новый контент, вы должны сделать именно это:

obj1.clearSet();
obj1.addSet(objTwoSet);

Обновление: Набор не рассматривается как отдельный дискретный объект в Hibernate. Это просто группировка сущностей, поэтому, когда вы говорите «удалить первый набор из базы данных», вы на самом деле говорите, что один из «удалить все сущности, содержащиеся в первом наборе из базы данных» или «разъединяет все сущности, содержащиеся в первый набор из заданного объекта в базе данных ".

Для первого вы бы использовали атрибут orphanRemoval @ OneToMany и увидели бы прототип родственных / дочерних отношений , продемонстрированный справочным руководством.

Для последнего вы просто делаете именно то, что делаете, но если это двунаправленные отношения, вы также должны правильно установить другой конец. Так что вместо простого:

obj1.addSet(objTwoSet);

вам нужно что-то вроде:

for (ObjectTwo o : obj1.getSet()) {
    o.setObjectOne(null);
}
obj1.addSet(objTwoSet);

Это, скорее всего, ваша проблема. Никогда нельзя оставлять свою объектную модель в сломанном состоянии.

1 голос
/ 23 декабря 2011

Попробуйте следующую реализацию:

public class ObjectOne{
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval=true)
  Set<ObjectTwo> obj2;

  public void addSet(Set<ObjectTwo> newSet){
    obj2.clear();
    obj2.addAll(newSet);
  }
}

Является ли связь двунаправленной, то есть ссылается ли ObjectTwo на ObjectOne?Если это так, вы должны также установить эту ссылку на ноль, прежде чем очистить набор obj2.

public class ObjectOne{
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval=true)
  Set<ObjectTwo> obj2;

  public void addSet(Set<ObjectTwo> newSet){
    for (ObjectTwo two : obj2) {
      two.setObjectOne(null);
    }
    obj2.clear();
    for (ObjectTwo two : newSet) {
      two.setObjectOne(this);
      obj2.add(two);
    }
  }
}
...