如何从EclipseLink的ClassDescriptor中获取待删除记录的ID值?
软删除定制器添加删除者信息的实现方案
现有运行的软删除定制器代码
public class SoftDeleteCustomizer implements DescriptorCustomizer { @Override public void customize(ClassDescriptor descriptor) { descriptor.getQueryManager().setDeleteSQLString( String.format("UPDATE %s SET record_status = 'D', record_status_time = CURRENT_TIMESTAMP WHERE id = #ID", descriptor.getTableName() ) ); } }
需求与问题
需要在软删除操作中添加记录删除者的信息,倾向于用参数方式传递,但使用DeleteObjectQuery时,不知道如何获取待删除记录的ID/主键值来设置参数。当前尝试的代码如下:
@Override public void customize(final ClassDescriptor descriptor) { final DeleteObjectQuery query = new DeleteObjectQuery(); query.addArgument("DELETED_BY", String.class); query.addArgument("ID", Long.class); query.addArgumentValue(SecurityUtils.getUsername()); query.addArgumentValue(...); // 不知道如何获取待删除记录的ID query.setSQLString(String.format(DELETE_SQL, descriptor.getTableName())); descriptor.getQueryManager().setDeleteQuery(query); }
解决方案
不需要手动添加ID参数并赋值,EclipseLink的DeleteObjectQuery会自动处理主键参数绑定。可以通过查询事件动态注入删除者信息,同时利用框架特性自动绑定主键值,具体实现如下:
方式一:适配任意主键(单/复合主键)
public class SoftDeleteCustomizer implements DescriptorCustomizer { private static final String DELETE_SQL_TEMPLATE = "UPDATE %s SET record_status = 'D', record_status_time = CURRENT_TIMESTAMP, deleted_by = ? WHERE %s"; @Override public void customize(final ClassDescriptor descriptor) { // 动态构建主键WHERE子句,适配单/复合主键 List<DatabaseField> primaryKeyFields = descriptor.getPrimaryKeyFields(); StringBuilder whereClause = new StringBuilder(); for (int i = 0; i < primaryKeyFields.size(); i++) { DatabaseField field = primaryKeyFields.get(i); if (i > 0) { whereClause.append(" AND "); } whereClause.append(field.getName()).append(" = #").append(field.getName()); } // 构建完整软删除SQL String deleteSql = String.format(DELETE_SQL_TEMPLATE, descriptor.getTableName(), whereClause.toString()); // 配置DeleteObjectQuery DeleteObjectQuery deleteQuery = new DeleteObjectQuery(); deleteQuery.setSQLString(deleteSql); // 添加查询监听器,在执行前注入删除者信息 deleteQuery.addQueryListener(new QueryAdapter() { @Override public void prepareQuery(DatabaseQuery query, Record record, Session session) { DatabaseCall call = query.getDatabaseCall(); // 注入当前登录用户名到参数中 call.addArgumentValue(SecurityUtils.getUsername()); } }); descriptor.getQueryManager().setDeleteQuery(deleteQuery); } }
方式二:已知主键字段名(简化版)
如果确定实体主键字段名为id,可以直接写死占位符,代码更简洁:
public class SoftDeleteCustomizer implements DescriptorCustomizer { private static final String DELETE_SQL_TEMPLATE = "UPDATE %s SET record_status = 'D', record_status_time = CURRENT_TIMESTAMP, deleted_by = ? WHERE id = #id"; @Override public void customize(final ClassDescriptor descriptor) { String deleteSql = String.format(DELETE_SQL_TEMPLATE, descriptor.getTableName()); DeleteObjectQuery deleteQuery = new DeleteObjectQuery(); deleteQuery.setSQLString(deleteSql); deleteQuery.addQueryListener(new QueryAdapter() { @Override public void prepareQuery(DatabaseQuery query, Record record, Session session) { DatabaseCall call = query.getDatabaseCall(); call.addArgumentValue(SecurityUtils.getUsername()); } }); descriptor.getQueryManager().setDeleteQuery(deleteQuery); } }
关键说明
#字段名是EclipseLink的参数占位符,框架会自动从待删除实体中对应字段取值并绑定,无需手动设置ID参数。- 使用
QueryListener的prepareQuery方法注入删除者信息,该方法在查询执行前触发,能获取到当前上下文的用户名,避免在定制器初始化时无法获取动态数据的问题。
内容的提问来源于stack exchange,提问作者Jasper de Vries
相关产品推荐
相关产品推荐

