【问题标题】:Wrong type when searching from enum in collection in JPA从 JPA 集合中的枚举中搜索时类型错误
【发布时间】:2017-09-25 10:41:12
【问题描述】:

我的班级Role 有一个属性enumP 是:

@Convert(converter = EnumPConverter.class)
@Enumerated(EnumType.STRING)
private EnumP enumP;

这是转换器:

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

    @Override
    public String convertToDatabaseColumn(final EnumP attribute) {
        switch (attribute) {
        case X:
            return "X";
        case Y:
            return "Y";
        case Z:
            return "Z";
        default:
            throw new DbException("Type of enumeration is unknown at the time of conversion to a DB value.",
                    new IllegalArgumentException("Value received : " + attribute));
        }
    }


    @Override
    public EnumP convertToEntityAttribute(final String dbData) {
        switch (dbData) {
        case "X":
            return EnumP.X;
        case "Y":
            return EnumP.Y;
        case "Z":
            return EnumP.Z;
        default:
            throw new DbException("Unknown enumerated value was found in the DB",
                    new IllegalArgumentException("Value received : " + dbData));
        }
    }
}

这是枚举:

public enum EnumP {
    X, Y, Z;
}

当谓词是:

builder.isTrue(fromRole.get(Role_.enumP).in((Object[]) filter.getFilterSetValues()))

其中getFilterSetValues() 将返回一个字符串数组,如下所示:

["X", "Y"]

我得到以下异常:

Parameter value [X] did not match expected type [EnumP (n/a)]

我试图在转换器上添加一个行断点,但调试器并没有在该行停止。

PS:我无权修改Enum,所以任何操作都应该在转换器内部完成。

【问题讨论】:

  • 你的意思是@Convert(converter = EnumPConverter.class),对吧?
  • @crizzis 是的,对此感到抱歉

标签: java jpa enums jpa-2.0 criteria


【解决方案1】:

如果 X->X, Y->Y, Z->Z 的值相同,为什么要使用转换器? 我认为 @Enumerated(EnumType.STRING) 在您的情况下就足够了,无需转换它们。

我同意@crizzis,使用枚举的字符串值是一种不好的做法。更好的是实现您的 getFilterSetValues 以返回枚举值数组

【讨论】:

  • @AimadMAJDOU 或者,完全放弃@Enumerated。不要同时使用两者。 @Converter 的 javadocs 声明:'Convert 注释不应用于指定以下内容的转换:Id 属性、版本属性、关系属性和明确表示为 Enumerated 或 Temporal 的属性'
  • 是的,确实,正如我所说,转换器一开始就不起作用,因为调试器不会像我所说的那样在转换器内部的任何断点上停止,但我仍然得到那个异常,因为fromRole.get(Role_.enumProvenanceID) 将返回一个无法与filter.getFilterSetValues() 中的字符串值比较的枚举值
  • 谢谢,但fromRole.get(Role_.enumP) 将返回一个没有name 函数的Path
【解决方案2】:

由于Role.enumP 的类型为EnumPgetFilterSetValues() 返回一个字符串数组,因此存在明显的类型不匹配。您需要将 EnumP 的数组传递给 in() 方法。

【讨论】:

  • 这就是我的想法,但是我必须在EnumP 中创建某种函数,它将采用getFilterSetValues(),然后重新运行EnumP 的数组,但因为我没有无权修改EnumP,最好的办法是把fromRole.get(Role_.enumP)转成String值,而不是把接收到的String数组转过来。
  • JPA 不会为您这样做。您自己决定通过相应地映射 Role.enumP 将其视为枚举(而不是字符串)。如果您需要Role.enumP 作为字符串,请将其映射为字符串,否则在任何地方使用枚举。
  • 另外,我不明白你的意思是“我必须在EnumP 中创建某种函数,它将采用getFilterSetValues(),然后重新运行EnumP 的数组” - 为什么转换方法必须进入EnumP?也许还有一个更相关的问题 - 为什么getFilterSetValues() 首先要对字符串数组进行操作?
  • 所以我无法将fromRole.get(Role_.enumP) 转换为字符串值?如果我做了这样的事情呢:fromRole.&lt;String&gt; get("enumProvenanceID"),对于你的第二个问题,因为我将EnumP 与其他实体一起使用,而不仅仅是Role
  • @AimadMAJDOU BTW,EnumP 中已经实现了一种转换方法。它被称为EnumP.valueOf。话虽如此,让getFilterSetValues() 对字符串值进行操作仍然是一种不好的做法。使用枚举的重点是确保将值限制为预定义的集合。相同的验证逻辑如何不适用于从getFilterSetValues() 返回的数组?
猜你喜欢
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多