来自具有 属性 访问权限的外键的 JPA 复合主键

JPA composite primary key from foreign keys with property access

我是JPA新手,请多多关照

显然没有关于如何以 属性 访问方式从外键创建复合主键的问题。

问题

如果我使用下面示例中的 属性 访问类型,我是否还必须为引用的 FK 定义 getter 和 setter?

我认为情况并非如此,但 Java EE6 的 official documentation 确实如此。

Oracle® Containers for J2EE Enterprise JavaBeans Developer's Guide

A composite primary key class has the following characteristics:

  • It is a POJO class.
  • It must be public and must have a public no-argument constructor.
  • If you use property-based access, the properties of the primary key class must be public or protected.
  • It must be serializable.
  • It must define equals and hashCode methods.
  • The semantics of value equality for these methods must be consistent with the database equality for the database types to which the key is mapped.

You can make the composite primary key class either an embedded class owned by the entity class, or a nonembedded class whose fields you map to multiple fields or properties of the entity class. In the latter case, the names of primary key fields or properties in the composite primary key class and those of the entity class must correspond and their types must be the same.

我修改了这个例子,因为我想使用 FK。

Example 7-2 Embeddable Composite Primary Key Class

@Embeddable
public class EmployeePK implements Serializable {
    private String name;
    private long id;

    public EmployeePK() {
    }

    public String getName() {
        return name;
    }

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

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public int hashCode() {
        return (int) name.hashCode() + id;
    }

    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (!(obj instanceof EmployeePK)) return false;
        if (obj == null) return false;
        EmployeePK pk = (EmployeePK) obj;
        return pk.id == id && pk.name.equals(name);
    }
}

Example 7-3 JPA Entity With an Embedded Composite Primary Key Class

@Entity
@Access(AccessType.PROPERTY)
public class Employee implements Serializable {
    EmployeePK primaryKey;
 
    public Employee() {
    }
 
    @EmbeddedId
    public EmployeePK getPrimaryKey() {
        return primaryKey;
    }
 
    public void setPrimaryKey(EmployeePK pk) {
        primaryKey = pk;
    }
 
    @ManyToOne
    @MapsId("id")
    private classWithPKid fkobject1;

    @ManyToOne
    @MapsId("name")
    private classWithPKname fkobject2;
    ...
}

JPA 规范 (2.3.2) - 显式访问类型

When Access(PROPERTY) is applied to an entity class, mapped superclass, or embeddable class, mapping annotations may be placed on the properties of that class, and the persistence provider runtime accesses persistent state via the properties defined by that class. All properties that are not annotated with the Transient annotation are persistent. When Access(PROPERTY) is applied to such a class, it is possible to selectively designate individual attributes within the class for instance variable access. To specify a persistent instance variable for access by the persistence provider runtime, that instance variable must be designated Access(FIELD). The behavior is undefined if mapping annotations are placed on any instance variables defined by the class for which Access(FIELD) is not specified. Persistent state inherited from superclasses is accessed in accordance with the access types of those superclasses.

JPA 规范 (2.3.3) - 可嵌入的访问类型 Class

The access type of an embeddable class is determined by the access type of the entity class, mapped superclass, or embeddable class in which it is embedded (including as a member of an element collection) independent of whether the access type of the containing class has been explicitly specified or defaulted. A different access type for an embeddable class can be specified for that embeddable class by means of the Access annotation as described above.

当实体 class 的 AccessType 设置为 属性 时,提供程序将使用这些方法来获取持久状态和映射数据。当 class 的 AccessType 为 属性 时,持久性提供程序没有义务在字段上查找映射注释。另外,请注意 AccessType 由 Embedded class 继承,这就是为什么 EmployeePK 也需要定义 getters/setters。根据规范中的说法,当实体 class 使用 Access(属性) 时,您应该执行以下操作之一:

  1. 为 FK 字段定义 getter/setter 方法并将映射放置在 getter 方法上

    示例:

    @Entity
    @Access(AccessType.PROPERTY)
    public class Employee {
        private EmployeePK primaryKey;
    
        private ClassWithPKid fkobject1;
    
        @EmbeddedId
        public EmployeePK getPrimaryKey() {
            return primaryKey;
        }
    
        @ManyToOne
        @MapsId("id")
        public ClassWithPKid getFkobject1() {
            return fkobject1;
        }
    }
    
  2. 或者,在持久字段上显式定义 Access(FIELD)

    示例:

    @Entity
    @Access(AccessType.PROPERTY)
    public class Employee {
        private EmployeePK primaryKey;
    
        @ManyToOne
        @MapsId("id")
        @Access(AccessType.FIELD)
        private ClassWithPKid fkobject1;
    
        @EmbeddedId
        public EmployeePK getPrimaryKey() {
            return primaryKey;
        }
    }