JPAContainer OneToMany does not delete detail rows

Hi,

I am using Vaadin 7.0.4., JPAContainer 3.0.0, JBoss 6.1.0 (which is AS 7.2.0), Hibernate JPA, Postgresql 9.2
I have created two entities:


@Entity
public class Test {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Version
  private Long version;

  @OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, cascade = {CascadeType.ALL},  mappedBy = "test")
  private Set<TestLine> lines = new HashSet<TestLine>();
  ....

@Entity
@Table(name="test_line")
public class TestLine {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Version
  private Long version;

  @ManyToOne
  @JoinColumn(name="test_id", nullable = false)
  private Test test;
  ....
 

then basing on example BasicCrudView I have created my crudview (main fragments below):


public class BaseCrudView<T, K> extends VerticalLayout
    implements View, Property.ValueChangeListener, Button.ClickListener { 

  private enum FormEditMode {
    UNKNOWN,
    ADD,
    EDIT
  }

  private FormEditMode formEditMode = FormEditMode.UNKNOWN;

  private static final String ID = "id";
  private static final String VERSION = "version";

  private JPAContainer<T> jpaContainer;
  private FieldFactory fieldFactory;

  private Class<T> masterEntityClass;
  private Class<K> detailEntityClass;

  List<String> editableMasterPropertiesAdd;
  List<String> editableMasterPropertiesEdit;
  List<String> editableDetailProperties;

  private Panel panel;
  private Table table;
  private Form form;
  private Button btnFormCommit;
  private Button btnFormDiscard;
  private Button btnAddItem;
  private Button btnDeleteItem;

  @Override
  public void enter(ViewChangeListener.ViewChangeEvent aViewChangeEvent) {
  }

  public BaseCrudView(Class<T> aMasterEntity, Class<K> aDetailEntity) {
    masterEntityClass = aMasterEntity;
    detailEntityClass = aDetailEntity;
    initContainer();
    initFieldFactory();
    buildView();
  }

  protected void initContainer() {
    jpaContainer = JPAContainerFactory.makeJndi(getMasterEntityClass());
    table = new Table(null, jpaContainer);
  }

  protected void initFieldFactory() {
    fieldFactory = new FieldFactory();
  }


  protected String getDisplayEntityName() {
    return getMasterEntityClass().getSimpleName();
  }

  protected void buildView() {

    setSizeFull();

    panel = new Panel("Edycja : " + getDisplayEntityName());
    panel.setSizeFull();
    addComponent(panel);

    VerticalSplitPanel pVerticalSplitPanel = new VerticalSplitPanel();
    pVerticalSplitPanel.setSizeFull();

    HorizontalLayout pMasterTableButtons = new HorizontalLayout();

    btnAddItem = new Button("+", this);
    btnAddItem.setDescription("Dodaj " + getDisplayEntityName());
    btnAddItem.setStyleName(Reindeer.BUTTON_SMALL);
    pMasterTableButtons.addComponent(btnAddItem);

    btnDeleteItem = new Button("-", this);
    btnDeleteItem.setDescription("Usuń zaznaczone " + getDisplayEntityName());
    btnDeleteItem.setStyleName(Reindeer.BUTTON_SMALL);
    btnDeleteItem.setEnabled(false);
    pMasterTableButtons.addComponent(btnDeleteItem);

    VerticalLayout pMasterTableAndButtonsLayout = new VerticalLayout();
    pMasterTableAndButtonsLayout.addComponent(pMasterTableButtons);

    table.setSizeFull();
    table.setSelectable(true);
    table.addValueChangeListener(this);
    table.setImmediate(true);
    pMasterTableAndButtonsLayout.addComponent(table);

    pVerticalSplitPanel.addComponent(pMasterTableAndButtonsLayout);

    form = new Form();
    form.setVisible(false);
//    form.setBuffered(true);
    form.setCaption(getDisplayEntityName());
    form.setFormFieldFactory(fieldFactory);

    btnFormCommit = new Button("Zapisz", this);
    btnFormDiscard = new Button("Anuluj", this);
    form.getFooter().addComponent(btnFormCommit);
    form.getFooter().addComponent(btnFormDiscard);
    ((HorizontalLayout) form.getFooter()).setSpacing(true);

    pVerticalSplitPanel.addComponent(form);
    pVerticalSplitPanel.setSplitPosition(50f, Unit.PERCENTAGE);

    panel.setContent(pVerticalSplitPanel);

  }

  protected T newMasterEntityInstance() {
    T pNewInstance = null;
    try {
      pNewInstance = getMasterEntityClass().newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
      e.printStackTrace();
    }
    return pNewInstance;
  }

  @Override
  public void buttonClick(Button.ClickEvent event) {
    if (event.getButton() == btnAddItem) {
      addItem();
    } else if (event.getButton() == btnDeleteItem) {
      deleteItem(table.getValue());
    } else if (event.getButton() == btnFormCommit) {
      formCommit();
    } else if (event.getButton() == btnFormDiscard) {
      formDiscard();
    }
  }

  @Override
  public void valueChange(Property.ValueChangeEvent event) {
    editItem(event.getProperty().getValue());
  }


  protected void addItem() {

    checkPendingFormEdit();

    formEditMode = FormEditMode.ADD;
    fieldFactory.setVisibleProperties(getMasterEntityClass(), editableMasterPropertiesAdd.toArray(new String[0]
));
    T pNewEntity = newMasterEntityInstance();
    EntityItem pNewItem = jpaContainer.createEntityItem(pNewEntity);
    form.setVisible(true);
    form.setItemDataSource(pNewItem, editableMasterPropertiesAdd);
    form.focus();
  }

  protected void editItem(Object aItemId) {

    checkPendingFormEdit();

    formEditMode = FormEditMode.EDIT;
    fieldFactory.setVisibleProperties(getMasterEntityClass(), editableMasterPropertiesEdit.toArray(new String[0]
));
    Item pSelectedItem = table.getItem(aItemId);
    boolean pIsSelection = pSelectedItem != null;
    btnDeleteItem.setEnabled(pIsSelection);
    form.setVisible(pIsSelection);
    if (pIsSelection) {
      form.setItemDataSource(pSelectedItem,editableMasterPropertiesEdit);
      form.focus();
    }
  }

  protected void deleteItem(Object aItemId) {
    checkPendingFormEdit();
    jpaContainer.removeItem(aItemId);
  }

  protected void formCommit() {
    form.commit();
    Object pItemId = null;
    if (formEditMode == FormEditMode.ADD) {
      T pEntity = ((EntityItem<T>) form.getItemDataSource()).getEntity();
      pItemId = jpaContainer.addEntity(pEntity);
    } else {
      pItemId = ((EntityItem<T>) form.getItemDataSource()).getItemId();
    }
    form.setVisible(false);
    formEditMode = FormEditMode.UNKNOWN;
    table.setValue(pItemId);
  }

  protected void formDiscard() {
    form.discard();
    form.setVisible(false);
    formEditMode = FormEditMode.UNKNOWN;
  }

editableMasterPropertiesEdit, editableMasterPropertiesEdit, editableDetailProperties are all properties from entities
despite id, version. Additionally editableMasterPropertiesEdit property id collection has the mappedBy property field “lines”.

All works fine despite deleting rows from JPAContainer’s MasterDetailEditor. I have checked the JPA code and it works:


    Test pTest = new Test();
    pTest.setTekst("testEjb1");
    pTest.setTestDate(Calendar.getInstance().getTime());

    TestLine pTestLine = new TestLine();
    pTestLine.setTekst("testEjb1ts");
    pTestLine.setTestDouble(1d);
    pTestLine.setTest(pTest);

    pTest.getLines().add(pTestLine);

    em.persist(pTest);

    Test pTest = em.find(Test.class, 21L);
    for (TestLine pTestLine : pTest.getLines()) {
      pTestLine.setTest(null);
    }
    pTest.getLines().clear();
    em.persist(pTest);

On debug the detail line (TestLine) is removed from the master Item (Test field lines) but the changes are not populated to the database
after form.commit(); I have checked the MasterDetailEditor code but it seems ok for me (as for few hours of looking).
Any ideas where to look for missing delete’s.

thanks for help
greetings
Marcin

Additionally I have check that the:
((EntityItem) form.getItemDataSource()).getEntity() - returns the updated entity with deleted rows
but
jpaContainer.getItem(((EntityItem) form.getItemDataSource()).getItemId()).getEntity(); - returns not updated
entity with not deleted TestLine objects from lines mappedBy collection set

I have checked the Vaadin 7 book example on master-detail editor and on the example the deleting is also not working.
In my case there was no exception after pressing delete so the reason may be different.


http://demo.vaadin.com/book-examples-vaadin7/book/#jpacontainer.fieldfactory.formonetoone

Similar problem, there is a solution ore explanation?

If there are problems with deletion of detail rows despite correct cascade and orphan removal settings (which seem to be present in the original post), please
create a ticket
(or two if there is a separate issue with deletion more generally) with a minimal example permitting reproducing the problem and information about the versions used etc. Furthermore, the ticket could also contain a link to this thread if relevant.