【问题标题】:OpenJpa - Incomprehensible exception creating a named-native-queryOpenJpa - 创建命名本机查询的难以理解的异常
【发布时间】:2023-03-17 00:25:02
【问题描述】:

OpenJPA 1.2.2、WebSphere 7 (Java EE 5)

我正在尝试使用 orm.xml 中定义的 named-native-query 将表映射到 POJO(不是实体!):

<named-native-query name="myNativeQuery" result-class="foo.bar.PojoBean">
    <query>
        SELECT col_one AS colOne, col_two AS colTwo, col_three AS colThree 
        FROM myTable WHERE id = 42
    </query>
</named-native-query>

PojoBean 是一个带有 String getter/setter 和空参数构造函数的 final 类:

public final class PojoBean implements java.io.Serializable {

    public PojoBean() {
    }

    public String getColOne() { ... }
    public void setColOne(String colOne) { ... }
    ...
}

当我创建查询时:

EntityManager myEntityManager = ...
myEntityManager.createNamedQuery("myNativeQuery");

我遇到了一个异常(为便于阅读而格式化):

<openjpa-1.2.2-r422266:898935 nonfatal user error>  
org.apache.openjpa.persistence.ArgumentException: 
Result type "class foo.bar.PojoBean" does not have any public fields or setter methods for the projection or aggregate result element "null", 
nor does it have a generic put(Object,Object) method that can be used, 
nor does it have a public constructor that takes the types null.

这是什么意思?

更多信息:

  • PojoBean 的实现无法更改,并且作为 final 类也无法扩展。
  • 使用 EntityManager.createNativeQuery(...) 从 java 运行查询是可行的,但这不是一个选项。

谢谢,

【问题讨论】:

  • 你有一个顽固的二传手吗?类似于 setValue(String val) setVatue(Integer val)。如果您的查询返回 null,则可能是 abigiuos,应该调用哪个 setter。
  • 没有模棱两可的二传手。如果我在 Java (EntityManager.createNativeQuery(...)) 上编写查询而不是使用 orm.xml 它可以工作。
  • 为了咯咯笑,你能试着让你的 POJO 不是最终的吗?另外,您的 orm sn-p 显示您的查询是本机查询,您为什么不调用 createNativeQuery(...)?
  • 我也尝试将 POPJO 设置为非决赛,但没有运气。我不想使用 createNativeQuery(...):查询存储在 orm.xml 中并根据某些参数调用(“约定优于配置”)

标签: java openjpa


【解决方案1】:

您可能希望确保已部署 JAR 中的 PojoBean 类实际上具有公共 setter 和 getter。

【讨论】:

  • Getter/Setter 是公开的。如果我按照异常中的建议手动添加一个通用的“put(Object,Object)”方法,它似乎可以工作,但这种解决方案是不可接受的。
  • 你能检查一下你没有在 Bean 中使用原语(int、long 等)吗? JPA 可能会遇到设置 null -'为投影或聚合结果元素“null”'的问题
  • 没有原语,bean 只使用字符串。数据库 (Oracle) 中的列也被定义为 VARCHAR2。
  • 某些东西肯定会从查询中返回为 null。也许您可以在 SQL 提示符下运行相同的查询,看看什么是“空”。 OpenJPA 在设置“null”时遇到问题
  • 即使使用已知不为空的值(主键)也不能解决问题。唯一的方法是实现一个甚至不会被调用的虚拟(空)“put(Object,Object)”方法。但这不是解决方案,我无法修改 POJO :(
【解决方案2】:

我遇到了同样的例外。我的问题是,persistence.xml 中的persistence-unit 名称是错误的。在这种情况下,异常并不完全指向正确的方向......

【讨论】:

    【解决方案3】:

    问题在于 openJPA 不会自动将 underscore_names 映射到 cameCaseName,因此必须提供翻译才能填写您的 POJO。

    在你的情况下 col_one => colOne,但 openJPA 不知道。

    我所做的是实现通过反射将值分配给相应字段的通用设置器,并在Google Guava 的一些帮助下进行字符串转换:

    public void put(Object field, Object value) {
    
        try {
    
            String fieldName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, field.toString());
            Field f = this.getClass().getDeclaredField(fieldName);
            f.set(this, value);
    
        }
        catch(Exception e) {
            logger.error("ERROR: " + e.getMessage());
        }
    
    }
    

    我必须说我不太喜欢这个解决方案,但它确实很好用。有没有办法实现一些接口或使用@Annotation 来连接它?

    另一种方法是使用每个 pojo 扩展的抽象类。在这种情况下,您应该使用 setter 方法,因为该字段可能是私有的。

    public abstract class JpaPutter  {
    
    
        public void put(Object field, Object value) {
    
            try {
    
                String methodName = "set" + CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, field.toString());
                this.getClass().getMethod(methodName, value.getClass()).invoke(this,  value);
    
            }
            catch(Exception e) {
                throw new RuntimeException(e);
            }
    
        }   
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-13
      • 2019-03-27
      • 1970-01-01
      • 1970-01-01
      • 2012-09-21
      • 2012-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多