JavaFX上下文中的JPA

JavaFX上下文中的JPA,jpa,javafx,Jpa,Javafx,到目前为止,我在托管容器中使用了JPA,但目前我正在使用JavaFX和JPA开发一个桌面应用程序,我必须管理事务。我有一个具有多个javafx窗口的应用程序: 第一个窗口:在列表中显示一些项目(条目) 单击条目时,它会显示该项目的一些详细信息(详细信息视图) 在“详细信息”视图中,可以添加有关该项目的一些信息(详细信息表单) 首先,我创建了一个项目,该项目将列在条目视图中。然后我进入该项目的详细视图。在details视图中,我通过填写第三个视图添加了一个新条目。我单击enter,详细信息视图

到目前为止,我在托管容器中使用了JPA,但目前我正在使用JavaFX和JPA开发一个桌面应用程序,我必须管理事务。我有一个具有多个javafx窗口的应用程序:

  • 第一个窗口:在列表中显示一些项目(条目)
  • 单击条目时,它会显示该项目的一些详细信息(详细信息视图)
  • 在“详细信息”视图中,可以添加有关该项目的一些信息(详细信息表单)
首先,我创建了一个项目,该项目将列在条目视图中。然后我进入该项目的详细视图。在details视图中,我通过填写第三个视图添加了一个新条目。我单击enter,详细信息视图将使用该信息进行更新。然后我离开details视图,在条目页面中有一个关于整个项目的摘要。这一切都很好。然后我再次进入details视图并编辑表单中的一些内容(步骤3)。单击“确定”时,详细信息视图将更新。然后,我离开details视图返回到entry页面,但摘要没有更新

因此,我的问题实际上是,在更新详细信息时,条目页面没有更新(在我第一次创建详细信息时,条目页面被正确更新)

一些代码

条目页面[1]打开详细信息页面,如下所示:

protected void showActivities(Project project, Window window) {
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("ProjectActivities.fxml"));
        Stage stage = ModalDialogHelper.createNewModal("Project Activity Log", loader, window);
        ProjectActivityController pac = loader.getController();
        project = projectDataService.detach(project);
        pac.setProject(project);
        pac.onPostLoad();
        stage.showAndWait();
        projectDataService.merge(project);
        onReload();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
详细信息页面(ProjectActivities.fxml[2])在新窗口中打开表单[3]e,如下所示(由窗口上的按钮触发):

我提交表格[3](ActivityLogForm.fxml)时附带以下代码:

@FXML
private void saveActivity(ActionEvent event) {
    if (activity == null) {
        activity = new Activity();
        activity.setProject(project);
        project.getActivities().add(activity);
    } else {
        activityDataService.merge(activity);
    }
    activity.setBegin(getBegin());
    activity.setStop(getStop());
    if (activity.getLog() == null) {
        Log log = new Log();
        activity.setLog(log);
    }
    if (details != null) {
        activity.getLog().setDetails(details.getText());
    }
    if (activity.getId() > 0) {
        activity = activityDataService.merge(activity);
    } else {
        activityDataService.persist(activity);
    }
    activityDataService.detach(activity);
    ModalDialogHelper.close(((Node) event.getSource()).getScene().getWindow());
}
更多信息

条目视图[1]显示VBox中的项目列表。单击项目时,将打开一个新窗口(详细视图[2]),单击的项目将传递给该视图的详细视图控制器。在详细信息视图中,可以打开一个新表单(窗口[3])来输入详细信息。通过提交表单,详细信息将在详细信息视图[2]中按需要更新。然后我退出details视图,主视图[1]按预期更新。然后,我回到同一个项目的细节,并希望更改细节表单[3]中的一些内容(与之前创建新细节的表单相同)。我提交了更改,详细信息视图[2]得到了正确更新,但随后我退出了详细信息视图并返回到主视图[1]。但是现在在这个视图中,我看不到我刚才所做的更改,而是将它们写入数据存储

更新 我忘了说我正在使用EclipseLink,下面是我的通用数据服务:

public abstract class AbstractDataService<T> {

protected EntityManager entityManager;
protected int pageSize;

protected Class<T> type;

public AbstractDataService(Class<T> clazz) {
    this.type = clazz;
    init();
}

protected void init() {
    EntityManagerFactory factory = Persistence.createEntityManagerFactory("ttUnit");
    entityManager = factory.createEntityManager();
    setPageSize(Integer.parseInt(Resources.getString("settings.pagination.default"), 10));
}

public T find(Object o) {
    return entityManager.find(type, o);
}

public List<T> findAll() {
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<T> query = builder.createQuery(type);
    Root<T> entities = query.from(type);
    return entityManager.createQuery(query.select(entities)).getResultList();
}

public List<T> getPage(int page) {
    if (isPageOutOfBounds(page)) {
        page = correctPage(page);
    }
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<T> query = builder.createQuery(type);
    Root<T> entities = query.from(type);
    return entityManager.createQuery(query.select(entities)).setFirstResult(getFirstResult(page))
            .setMaxResults(pageSize).getResultList();
}

private boolean isPageOutOfBounds(int page) {
    int pageCount = getPages();
    return page < 0 || (pageCount > 0 && page > pageCount);
}

private int correctPage(int page) {
    int pageCount = getPages();
    if (page < 0) {
        page = 1;
    }
    if (pageCount > 0) {
        while (page > pageCount) {
            page--;
        }
    } else {
        // reset to the first page
        page = 1;
    }
    return page;
}

public int getPages() {
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Long> query = builder.createQuery(Long.class);
    Expression<Long> entities = builder.count(query.from(type));
    long count = entityManager.createQuery(query.select(entities)).getSingleResult();
    int pageCount = (int) Math.ceil((double) count / (double) pageSize);
    return pageCount;
}

public int getFirstResult(int page) {
    return (page - 1) * pageSize;
}

public T merge(T obj) {
    try {
        entityManager.getTransaction().begin();
        return entityManager.merge(obj);
    } finally {
        entityManager.getTransaction().commit();
    }
}

public void persist(T obj) {
    try {
        entityManager.getTransaction().begin();
        entityManager.persist(obj);
    } finally {
        entityManager.getTransaction().commit();
    }
}

public void remove(T obj) {
    try {
        entityManager.getTransaction().begin();
        entityManager.remove(obj);
    } finally {
        entityManager.getTransaction().commit();
    }
}

public void flush() {
    try {
        entityManager.getTransaction().begin();
        entityManager.flush();
    } finally {
        entityManager.getTransaction().commit();
    }
}

public T detach(T obj) {
    entityManager.detach(obj);
    return obj;
}

public void clear() {
    entityManager.clear();
}

/**
 * @return the pageSize
 */
public int getPageSize() {
    return pageSize;
}

/**
 * @param pageSize
 *            the pageSize to set
 */
public void setPageSize(int pageSize) {
    this.pageSize = pageSize;
}

我已经找到了解决办法。问题是,当我创建一个新活动时,传递给
createActivityEditor
中的
ActivityLogController
的活动为空。这意味着我仅在编辑实体时合并实体,但如果创建了新活动,我不会合并项目:

protected void createActivityEditor(Window window, Activity activity) {
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("ActivityLogForm.fxml"));
        Stage stage = ModalDialogHelper.createNewModal("Create A New Activity...", loader, window);
        ActivityLogController controller = loader.getController();
        controller.setProject(project);
        controller.setActivity((activity != null) ? activityDataService.detach(activity) : activity);
        controller.onPostLoad();
        stage.showAndWait();
        if (activity != null) {
            // re-attach the existing activity
            activity = activityDataService.merge(activity);
        } else {
            // the activity did not yet exist but the project needs to be
            // merged with the new activity
            project = projectDataService.merge(project);
        }
        onReload();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
与此类似,项目与底层数据库同步,并且知道该新活动。因此,将合并进一步的更改,因为活动不为null,并且活动实体中的项目属性标记为cascade=MERGE


也许它能帮助有类似问题的人,谢谢你的帮助

你在使用可观察数据吗?我是JavaFX新手。。。我看到容器(比如gridpane之类的)正在使用observeble。我想问题出在我对JPA的使用上。我想当我调用showAndWait时,它会启动一个新线程。是吗(我没有调试它)?没有阶段启动应该是好的。你使用任何你可以听的属性吗?我没有ui没有正确更新的问题。。。问题在于,数据库中分别位于持久性上下文/缓存中的实体与我预期的不同。顺便说一句:关于如何避免使用showAndWait()而将show()用于回调,我没有找到好的文档。您知道JavaFX中关于回调、事件系统的链接吗?或者我需要自己实现它吗?
Project 
| 1 (- activities (Cascade: ALL))
|  
| 0..n
Activity
   - project (Cascade: MERGE, DETACH)
protected void createActivityEditor(Window window, Activity activity) {
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("ActivityLogForm.fxml"));
        Stage stage = ModalDialogHelper.createNewModal("Create A New Activity...", loader, window);
        ActivityLogController controller = loader.getController();
        controller.setProject(project);
        controller.setActivity((activity != null) ? activityDataService.detach(activity) : activity);
        controller.onPostLoad();
        stage.showAndWait();
        if (activity != null) {
            // re-attach the existing activity
            activity = activityDataService.merge(activity);
        } else {
            // the activity did not yet exist but the project needs to be
            // merged with the new activity
            project = projectDataService.merge(project);
        }
        onReload();
    } catch (IOException e) {
        e.printStackTrace();
    }
}