尽管 autoApply=false 和 属性 未使用 @Convert 注释,但仍在应用 JPA 属性转换器

JPA Attribute Converter being applied despite autoApply=false and property not annotated with @Convert

我正在处理的系统有一堆遗留数据,其中布尔值存储为 'Y''N'。新的 table 改为使用 BIT 列并简单地存储 01。否 table 混合了这两种方法。

为了支持旧的 tables,我们有以下转换器:

@Converter(autoApply = false)
public class BooleanToStringConverter implements AttributeConverter<Boolean, String> {

    private Logger.ALogger Log = Logger.of(BooleanToStringConverter.class);

    @Override
    public String convertToDatabaseColumn(final Boolean attribute) {
        Log.debug("Converting the boolean value {}", attribute);

        if (attribute == null) {
            return "N";
        }

        return attribute ? "Y" : "N";
    }

    @Override
    public Boolean convertToEntityAttribute(final String dbData) {
        return "Y".equalsIgnoreCase(dbData);
    }

}

因为这只需要应用于某些实体,所以 autoApply 属性 已设置为 false。

我现在正在创建一个全新的实体,有一个新的 table。它有两个布尔属性,都使用 BIT 列样式而不是 Y/N:

@Entity
@Table(name = "MyEntity")
public class MyEntity {

    @Id
    @Column(name = "MyEntityId")
    private Long id;

    @Column(name = "IsClosed")
    private Boolean closed;

    ...
}

请注意,我没有应用 @Convert 注释。

我有一个查询需要过滤掉实体关闭的所有行:

query.where().eq(CLOSED, Boolean.FALSE)

正是在这一点上,我的问题出现了。每当此查询是 运行 时,我都会看到来自 BooleanToStringConverter 的日志消息被写入日志,实际上,如果我转储从 MySQL 数据库执行的实际 SQL 那么我可以看到转换器确实应用于布尔值 属性,创建了以下 SQL 片段:

select <columns>
  from MyEntity t0
 where <other predicates>
   and t0.IsClosed = 'N'
 order by <order clause>

这显然是错误的 - 不应该应用转换器,它没有设置为自动并且关闭的 属性 没有用 @Convert 注释。

我试图通过创建第二个转换器来解决这个问题:

@Converter(autoApply = true)
public class BooleanConverter implements AttributeConverter<Boolean, Boolean> {

    private Logger.ALogger Log = Logger.of(BooleanConverter.class);

    @Override
    public Boolean convertToDatabaseColumn(final Boolean attribute) {
        Log.debug("Processing the value {}.", attribute);
        return attribute;
    }

    @Override
    public Boolean convertToEntityAttribute(final Boolean dbData) {
        return dbData;
    }
}

这导致两个转换器都应用于 属性,我看到两个调试语句都出现在日志中。

2019-07-29 14:19:53,994 [dispatcher-69] DEBUG BooleanConverter     Processing the value false.
2019-07-29 14:19:53,994 [dispatcher-69] DEBUG BooleanToStringConve I'm Converting the boolean value false

接下来我尝试明确设置转换器以在实体本身上使用(我希望这可能会改变应用转换器的顺序,以便它最终成为 true/false 尽管有其他转换器运行宁):

@Entity
@Table(name = "MyEntity")
public class MyEntity {

    @Id
    @Column(name = "MyEntityId")
    private Long id;

    @Convert(converter = BooleanConverter.class)
    @Column(name = "IsClosed")
    private Boolean closed;

    ...
}

结果完全一样;两个转换器都按顺序应用于值,BooleanToStringConverter 笑到最后并破坏了谓词。

我宁愿保留 BooleanToStringConverter,因为它可以减少处理遗留数据的痛苦,但除非我能弄清楚为什么在不应该应用它时它看起来很可能我会必须删除它。

我正在使用 Ebean 版本 4.1.3 和 Play! 2.6.21

我怎样才能阻止这个流氓转换器将自己应用到它无权接触的属性?

这是 Ebean 的(现在)已知限制,如 Issue 1777 在 Ebean 的 GitHub 页面上所述。在撰写本文时未计划修复。