在自定义持久化器的 sqlArgToJava 中处理 NULL 情况 class
handle NULL case inside sqlArgToJava of custom persister class
我在我的一个项目中使用 ormlite,我有一个 class A
和自定义类型 F
的字段 f
并且我有要求该字段 f
在任何情况下都不应该为空。所以我想在数据库文件
中的字段 f 为 NULL 时实例化 class F 的新对象
class A {
@DatabaseField(columnName = "xyz", persisterClass = FieldPersister.class)
F f;
public A() {
f = new F();
}
}
根据文档,我使用自定义持久化器 class FieldPersister
并尝试在那里进行空检查。
class FieldPersister extends StringType {
public Object javaToSqlArg(FieldType fieldType, Object javaObject) {
...
}
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
if (sqlArg == null) return new F();
else {
String value = (String) sqlArg;
return new F(value);
}
}
}
我试过调试程序,发现下面的方法中已经有null检查
resultToJava(FieldType fieldType, DatabaseResults results, int columnPos)
即使重写此方法也没有解决导致我提出问题的问题,有什么方法可以处理这种情况,还是我遗漏了部分难题?
使用 SSCCE 更新:
Even overriding this method didn't resolved the issue which leads to my question, is there any way to handle this situation or am I missing some part of the puzzle?
您漏掉了拼图的一部分,而且非常微妙。不幸的是 ResultSet.getInt(...)
方法 return 是 int
。为什么这很重要?因为 ORMLite 无法判断数据库中的字段是 NULL
还是原始字段。所以通常发生的情况是 ORMLite 从 ResultSet
获取结果,要求它由自定义转换器转换,然后 ORMLite 查看它是否为 null 并适当地调整值。也许有更好的方法来做到这一点。我需要考虑一下。
这里有几个解决方案。
在您的字段定义中添加 defaultValue = ""
。如果磁盘上有 NULL
值,这将无法处理这种情况,但如果您使用 dao.create(...)
,它将起作用。然后,您可以使用 FieldConverter.parseDefaultString(...)
定义要在字段为空时插入的默认对象。
在您的 A.getValue()
方法中,您在那里执行 null
检查,如果它为 null,则 return 一个 new SimpleStringProperty("")
。但是你的示例代码可能过于简单了。
破解方法是重写 resultToJava(...)
方法,使其类似于:
@Override
public Object resultToJava(FieldType fieldType, DatabaseResults results,
int columnPos) throws SQLException {
// remove the null check here so we can handle the null
Object value = resultToSqlArg(fieldType, results, columnPos);
return sqlArgToJava(fieldType, value, columnPos);
}
但您还需要覆盖以下内容,这是一个 hack。
@Override
public boolean isStreamType() {
// this forces the null check to be ignored
return true;
}
这是一个 hack,因为如果 ORMLite 巧妙地改变它处理 "stream" SQL 类型的方式,它可能会破坏你的代码。
在此处查看我的测试版本:CustomFieldNullTest.java。
我在我的一个项目中使用 ormlite,我有一个 class A
和自定义类型 F
的字段 f
并且我有要求该字段 f
在任何情况下都不应该为空。所以我想在数据库文件
class A {
@DatabaseField(columnName = "xyz", persisterClass = FieldPersister.class)
F f;
public A() {
f = new F();
}
}
根据文档,我使用自定义持久化器 class FieldPersister
并尝试在那里进行空检查。
class FieldPersister extends StringType {
public Object javaToSqlArg(FieldType fieldType, Object javaObject) {
...
}
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
if (sqlArg == null) return new F();
else {
String value = (String) sqlArg;
return new F(value);
}
}
}
我试过调试程序,发现下面的方法中已经有null检查
resultToJava(FieldType fieldType, DatabaseResults results, int columnPos)
即使重写此方法也没有解决导致我提出问题的问题,有什么方法可以处理这种情况,还是我遗漏了部分难题?
使用 SSCCE 更新:
Even overriding this method didn't resolved the issue which leads to my question, is there any way to handle this situation or am I missing some part of the puzzle?
您漏掉了拼图的一部分,而且非常微妙。不幸的是 ResultSet.getInt(...)
方法 return 是 int
。为什么这很重要?因为 ORMLite 无法判断数据库中的字段是 NULL
还是原始字段。所以通常发生的情况是 ORMLite 从 ResultSet
获取结果,要求它由自定义转换器转换,然后 ORMLite 查看它是否为 null 并适当地调整值。也许有更好的方法来做到这一点。我需要考虑一下。
这里有几个解决方案。
在您的字段定义中添加
defaultValue = ""
。如果磁盘上有NULL
值,这将无法处理这种情况,但如果您使用dao.create(...)
,它将起作用。然后,您可以使用FieldConverter.parseDefaultString(...)
定义要在字段为空时插入的默认对象。在您的
A.getValue()
方法中,您在那里执行null
检查,如果它为 null,则 return 一个new SimpleStringProperty("")
。但是你的示例代码可能过于简单了。破解方法是重写
resultToJava(...)
方法,使其类似于:@Override public Object resultToJava(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException { // remove the null check here so we can handle the null Object value = resultToSqlArg(fieldType, results, columnPos); return sqlArgToJava(fieldType, value, columnPos); }
但您还需要覆盖以下内容,这是一个 hack。
@Override public boolean isStreamType() { // this forces the null check to be ignored return true; }
这是一个 hack,因为如果 ORMLite 巧妙地改变它处理 "stream" SQL 类型的方式,它可能会破坏你的代码。
在此处查看我的测试版本:CustomFieldNullTest.java。