基于存储库方法在 JPA 中以不同方式处理数据
Handling data differently in JPA based on repository methods
在 Java Spring 应用程序中,我有一个 class 类似于以下内容:
class MyModel {
// other properties here
private Boolean accessAllowed;
public Boolen isAccessAllowed() {
return accessAllowed;
}
public void setAccessAllowed(Boolean accessAllowed) {
this.accessAllowed = accessAllowed;
}
public void updateAccessAllowedForResponse() {
// business logic to update `accessAllowed` only for read methods of repository
}
public void updateAccessAllowedForSave() {
// business logic to update `accessAllowed` only for write methods of repository
}
}
我们的想法是我们在数据库中使用三个值,即 null
或 true
或 false
并使用空值作为“默认值”,即用户没有进行选择。因此,如果 DB 中的值为空,我们 return 根据某些业务逻辑 true
或 false
。
问题是这个值只是为了响应或其他应用程序在“内存中”更新,但是 updateAccessAllowedForResponse()
之后实体的变化不应该在数据库中持续存在。
目前,我从存储库中的 Hibernate 会话中取消附加实体,例如
class MyRepository extends GenericRepository<MyModel> {
public MyModel get(Long id) {
MyModel instance = super.get(id);
Session session = entityManager.unwrap(Session.class);
session.evict(instance);
instance.updateAccessAllowedForResponse();
return instance;
}
public MyModel merge(MyModel instance) {
instance.updateAccessAllowedForSave()
return super.merge(instance);
}
}
这可行,但是上述方法存在一个大问题:我必须在很多地方重复这个。理想情况下,我希望能够在 MyModel 本身上定义此逻辑。也可以选择使用自定义存储库,但这是一个非常具体的用例,我们没有时间仅为此功能编写自定义存储库。
老实说,我是 Java / Spring 的新手。所以我希望有一些我无法通过谷歌搜索找到的方法。
您可以使用 Spring 事务来完成此操作,方法是创建两个单独的保存方法,一个具有 Spring Transactional
和 isolation = Isolation.SERIALIZABLE
,另一个没有。所以你的意思是你想强迫用户使用特定的保存点,无论他们是否想在交易中用不同的对象做其他事情。在这种情况下,强制提交,刷新,调用 yourPersistenceService.saveSecondaryObject(x)
什么的,然后你说 yourPersistenceService.savePrimaryObject(y)
之前总是需要调用。或者,对于 MyModel 对象,通过更新触发方法执行 pre-save 和 post-save。这应该由 Hibernate 自动发生,因此您有机会在其中跟踪此字段更改,并在持久化后设置字段。这与我遇到的 read-only 字段的情况相同,这些字段只需要为输出复制(数据库是 Postgres 12,我制作了一个副本 table 只是从一个到 read-only table 在一个便宜的触发器上。这样,每次模型更改时,它都会触发 Postgres 上的作业以更新 table)。
public MyModel get(Long id) {
MyModel instance = super.get(id);
Hibernate.initialize(instance.accessAllowed);
instance.flush();
return instance;
}
作为第三种选择,您可以让控制器处理所有这些,接收 JPA 对象,设置字段,然后将其发送到 JSP,而无需刷新或 re-loading任何东西。
在 Java Spring 应用程序中,我有一个 class 类似于以下内容:
class MyModel {
// other properties here
private Boolean accessAllowed;
public Boolen isAccessAllowed() {
return accessAllowed;
}
public void setAccessAllowed(Boolean accessAllowed) {
this.accessAllowed = accessAllowed;
}
public void updateAccessAllowedForResponse() {
// business logic to update `accessAllowed` only for read methods of repository
}
public void updateAccessAllowedForSave() {
// business logic to update `accessAllowed` only for write methods of repository
}
}
我们的想法是我们在数据库中使用三个值,即 null
或 true
或 false
并使用空值作为“默认值”,即用户没有进行选择。因此,如果 DB 中的值为空,我们 return 根据某些业务逻辑 true
或 false
。
问题是这个值只是为了响应或其他应用程序在“内存中”更新,但是 updateAccessAllowedForResponse()
之后实体的变化不应该在数据库中持续存在。
目前,我从存储库中的 Hibernate 会话中取消附加实体,例如
class MyRepository extends GenericRepository<MyModel> {
public MyModel get(Long id) {
MyModel instance = super.get(id);
Session session = entityManager.unwrap(Session.class);
session.evict(instance);
instance.updateAccessAllowedForResponse();
return instance;
}
public MyModel merge(MyModel instance) {
instance.updateAccessAllowedForSave()
return super.merge(instance);
}
}
这可行,但是上述方法存在一个大问题:我必须在很多地方重复这个。理想情况下,我希望能够在 MyModel 本身上定义此逻辑。也可以选择使用自定义存储库,但这是一个非常具体的用例,我们没有时间仅为此功能编写自定义存储库。
老实说,我是 Java / Spring 的新手。所以我希望有一些我无法通过谷歌搜索找到的方法。
您可以使用 Spring 事务来完成此操作,方法是创建两个单独的保存方法,一个具有 Spring Transactional
和 isolation = Isolation.SERIALIZABLE
,另一个没有。所以你的意思是你想强迫用户使用特定的保存点,无论他们是否想在交易中用不同的对象做其他事情。在这种情况下,强制提交,刷新,调用 yourPersistenceService.saveSecondaryObject(x)
什么的,然后你说 yourPersistenceService.savePrimaryObject(y)
之前总是需要调用。或者,对于 MyModel 对象,通过更新触发方法执行 pre-save 和 post-save。这应该由 Hibernate 自动发生,因此您有机会在其中跟踪此字段更改,并在持久化后设置字段。这与我遇到的 read-only 字段的情况相同,这些字段只需要为输出复制(数据库是 Postgres 12,我制作了一个副本 table 只是从一个到 read-only table 在一个便宜的触发器上。这样,每次模型更改时,它都会触发 Postgres 上的作业以更新 table)。
public MyModel get(Long id) {
MyModel instance = super.get(id);
Hibernate.initialize(instance.accessAllowed);
instance.flush();
return instance;
}
作为第三种选择,您可以让控制器处理所有这些,接收 JPA 对象,设置字段,然后将其发送到 JSP,而无需刷新或 re-loading任何东西。