JPA 透明间接和容器策略

Posted

技术标签:

【中文标题】JPA 透明间接和容器策略【英文标题】:JPA Transparent Indirection and Container Policies 【发布时间】:2014-07-24 02:28:06 【问题描述】:

假设我有以下简单的客户/订单实现:

由 Customer 类定义的客户记录。 每个客户可以有多个由 Order 类定义的订单。

借鉴here对透明间接和容器策略的解释here我对EclipseLink这些概念的理解如下:

透明间接允许我说

Customer customer = Customer.getCustomerById(1);
Set<Order> orders = customer.getOrders();

需要注意的两点是:

    间接允许延迟加载属性,因此客户的订单仅在第 2 行而不是第 1 行从数据库中获取。 我可以将客户的订单视为 Order 类型对象的 Set(或 Collection、List 或 Map)。

Container Policy 告诉 EclipseLink 应该为 Set 使用哪个实际类,因此它应该在上面的示例中实现 Set

这就是我对 EclipseLink 中透明间接和容器策略的理解。

我在尝试访问数据库时看到以下错误:

异常 [EclipseLink-148] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DescriptorException 异常描述:容器策略 [CollectionContainerPolicy(class org.eclipse.persistence.indirection.IndirectSet)] 与透明间接不兼容。 映射:org.eclipse.persistence.mappings.OneToManyMapping[orders] 描述符:RelationalDescriptor(my.model.Customer --> [DatabaseTable(Customer)])

我确定我在尝试调试的代码中有错误,但我没有指定错误中提到的 CollectionContainerPolicy,所以我假设 org.eclipse.persistence.indirection.IndirectSet 是默认值。但如果我使用的是默认策略,那么我不确定这个错误的原因可能是什么,或者我应该使用哪个策略。

现在,我只想知道我对上面提到的透明间接和容器策略的理解是否正确。

如果它是正确的,我可能在我的代码中遗漏了一些相对较小的东西(调用或配置选项等),但如果我不理解这些概念,那么显然我需要先做更多的研究。

客户模型

package my.model;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;


/**
 * The persistent class for the customer database table.
 *
 */
@Entity
@Table(name=Customer.TBL_NAME)
@NamedQueries(
    @NamedQuery(name=Customer.QRY_BY_NAME,query="Select object(a) from Customer a where " +
            "a.name=:" + Customer.PRM_NAME),
    @NamedQuery(name=Customer.QRY_ALL, query="select object(a) from Customer a")
)
public class Customer implements Serializable 
    private static final long serialVersionUID = 1L;

    // Table specific onstants
    public static final String TBL_NAME = "Customer";
    public static final String QRY_BY_NAME = TBL_NAME + ".byName";
    public static final String QRY_ALL = TBL_NAME + ".all";
    public static final String PRM_NAME = "name";

    private int id;
    private String name;
    private Set<Order> orders;

    public Customer() 
    


    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    public int getId() 
        return this.id;
    

    public void setId(int id) 
        this.id = id;
    


    public String getName() 
        return this.name;
    

    public void setName(String name) 
        this.name = name;
    


    //bi-directional many-to-one association to Order
    @OneToMany(mappedBy="customer")
    public Set<Order> getOrders() 
        return this.orders;
    

    public void setOrders(Set<Order> orders) 
        this.orders = orders;
    


订单型号

package my.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;


/**
 * The persistent class for the order database table.
 *
 */
@Entity
@Table(name=Order.TBL_NAME)
public class Order implements Serializable 
    private static final long serialVersionUID = 1L;

    // Table constants
    public static final String TBL_NAME = "Order";

    private int id;
    private Customer customer;

    public Order() 
    


    @Id
    public int getId() 
        return this.id;
    

    public void setId(int id) 
        this.id = id;
    


    //bi-directional many-to-one association to Customer
    @ManyToOne
    public Customer getCustomer() 
        return this.customer;
    

    public void setCustomer(Customer customer) 
        this.customer = customer;
    

【问题讨论】:

你能展示你的实体和映射吗?你是怎么配置的? 感谢您查看此内容。我不想陷入代码中,我希望先确认我的理解。但是,我已经添加了模型定义,所以如果您发现它们有问题,请告诉我。 您的理解是正确的,但不应该需要,因为这不是您在使用 JPA 时需要配置的东西。 EclipseLink 将根据属性的类型和惰性/急切设置来确定要使用的收集策略和实现,而且它似乎这样做是正确的。异常抛出错误,可能是由于类加载器问题,因此用于 init 的类加载器不是用于验证的类加载器,但我不知道这是怎么发生的。您需要查看它运行的环境,因为异常本身只是一种症状。 谢谢,这是一个非常明确的答案。我注意到其他人也面临类似的问题,以及 Glassfish 的其他类加载器问题。如果您认为这个问题不是太琐碎,请将您的最后一条评论作为答案发表,我会将其标记为我接受的答案。 【参考方案1】:

您的理解是正确的,但不需要,因为这不是您在使用 JPA 时需要配置的内容。 EclipseLink 将根据属性的类型和惰性/急切设置来确定要使用的收集策略和实现,而且它似乎这样做是正确的。异常抛出错误,可能是由于类加载器问题,因此用于 init 的类加载器不是用于验证的类加载器,但我不知道这是怎么发生的。您需要查看它运行的环境,因为异常本身只是一种症状

【讨论】:

以上是关于JPA 透明间接和容器策略的主要内容,如果未能解决你的问题,请参考以下文章

如何将继承策略与 JPA 注释和 Hibernate 混合使用?

什么是允许 RMI 和 JPA/Hibernate 同时工作的正确安全策略值设置

JPA继承方式

JPA主键生成策略

JPA中的主键生成策略

jpa table主键生成策略