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