【问题标题】:Way to use @Convert to convert key of a Map (JPA)?使用 @Convert 转换 Map (JPA) 键的方法?
【发布时间】:2015-07-03 21:52:38
【问题描述】:

我正在使用 Java 8 的 java.time.LocalDate,并希望将其转换为 sql date 以便可以持久化。这是我的转换器:

@Converter(autoApply = true)
public class LocalDatePersistenceConverter implements
    AttributeConverter<LocalDate, Date> {

        @Override
        public Date convertToDatabaseColumn(LocalDate attribute) {
        return java.sql.Date.valueOf(attribute);
        }

        @Override
        public LocalDate convertToEntityAttribute(Date dbData) {
        return dbData.toLocalDate();
        }

}

以下是它的使用方法:

@Entity
@Access(AccessType.FIELD)
public class MutualFund implements Serializable {

    @Id
    private final String schemeName;

    @Convert(attributeName="key",converter=LocalDatePersistenceConverter.class)
    @ElementCollection
    private Map<LocalDate, Price> nav;

    //Other fields and methods
}

当我尝试持久化 MutualFund 对象时,出现以下异常:

java.lang.IllegalStateException: @Convert placed on Map attribute [mypackage.MutualFund.nav] must define attributeName of 'key' or 'value'

这段代码有什么问题?请帮忙。谢谢。

【问题讨论】:

  • 这对我来说是正确的。您确定您正在运行您向我们展示的代码吗?不相关:schemeName 不应该是最终的。
  • @JBNizet 是的。但是,我没有在任何地方对“LocalDatePersistenceConverter”进行任何配置。它只是简单地注释,然后在 MutualFund 类中使用,如图所示。
  • 我已将 schemeName 作为最终名称,因为一旦宣布共同基金计划的名称在其生命周期内不会改变。
  • 确实如此:JPA 首先通过调用其无参数构造函数来实例化实体,然后使用反射设置字段的值。
  • 是的,但从逻辑上讲它不会改变。我不希望任何人在任何时候都只是设置共同基金的名称。对于 JPA,我提供了带有打包私有访问权限的无参数构造函数。

标签: java jpa converter


【解决方案1】:

您的地图映射未完成,因此您遇到了异常。

地图映射有两种选择,不确定您要实现哪一种。

A) 导航地图的 LocalDate 键是 Price 对象的一个​​字段:

@Embeddable
public class Price implements Serializable {
    @Convert(converter=LocalDatePersistenceConverter.class) 
    //you don't need @convert if it is annotated with @Converter(autoApply = true)
    public LocalDate mark;
    public double price;
}

然后在你的集合映射中你需要指定使用的关键字段:

@ElementCollection
@MapKey(name="mark")
public Map<LocalDate, Price> nav;

B) nav 的关键元素不是 Price 对象的一部分,那么您需要将其显式映射到列:

@Embeddable
public class Price implements Serializable {
    public double price;
}

以及地图标注:

@Convert(converter=LocalDatePersistenceConverter.class)
@ElementCollection
@MapKeyColumn(name="mark")
public Map<LocalDate, Price> nav;

编辑 原来Hibernate比EclipseLink要求最高

使用@Converter(autoApply = true),它无需指向具有显式和隐式键列的转换器即可工作。

@ElementCollection
@MapKeyColumn(name="mark") //this annotation can be omitted then the key column is called nav_KEY
public Map<LocalDate, Price> nav;

没有自动应用,我无法让它工作。只有在使用 attributeName="key." 声明转换器时才能构建持久性上下文:

@Convert(attributeName="key.", converter=LocalDatePersistenceConverter.class)
@ElementCollection
public Map<LocalDate, Price> nav = new HashMap<>();

但转换器未正确应用。在模式生成期间,尝试将键列生成为 BLOB(由于没有给出长度而失败),并且在插入/获取期间触发了序列化而不是转换。我找不到解决方法。

【讨论】:

  • 你好 Zielu,我的情况是第二个。我尝试了您的解决方案,但仍然遇到同样的异常。
  • 我用EclipseLink测试过,你用的是哪个JPA?它也可以在没有转换注释的情况下工作(当 @Converter(autoApply = true) 在转换器类上时),因此您可以尝试将其删除。在我的示例中,我没有使用属性 name=key。
  • 也不要使用键作为列的名称@MapKeyColumn(name="key"),虽然没有保留键 我发现查询键是否用作字段/列名时存在问题。
  • 我正在使用休眠。我尝试了所有组合,但它抛出了相同的异常:( .
  • 我明天用hibernate试试
猜你喜欢
  • 2020-02-07
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多