两个嵌套@Embeddable的JPA映射问题

sen*_*eft 4 hibernate jpa

当Hibernate尝试为Item创建映射时,下一个Exception会抛出http://pastebin.com/RdysJeiU

异常的原因是列号和实际属性号不匹配.

接下来是数组的内容:

columnAliases = [IMAGE_TITLE]
propertyNames = [imageMetadata,title]
Run Code Online (Sandbox Code Playgroud)

-

org.hibernate.persister.collection;

public abstract class AbstractCollectionPersister

private void initCollectionPropertyMap(String aliasName, Type type, String[] columnAliases, String[] columnNames) {

    collectionPropertyColumnAliases.put( aliasName, columnAliases );
    collectionPropertyColumnNames.put( aliasName, columnNames );

    if ( type.isComponentType() ) {
        CompositeType ct = (CompositeType) type;
        String[] propertyNames = ct.getPropertyNames();
        for ( int i = 0; i < propertyNames.length; i++ ) {
            String name = propertyNames[i];
            collectionPropertyColumnAliases.put( aliasName + "." + name, columnAliases[i] );
            collectionPropertyColumnNames.put( aliasName + "." + name, columnNames[i] );
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

Photo实体的映射完整无误.

为什么Hibernate无法映射Item实体的@Embeddable集合属性的@Embeddable Image类的imageMetadata属性?

package model.dao.mappings; import javax.persistence.*;

@MappedSuperclass
public class BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
protected long id;

public BaseEntity() {}

public long getId() {
    return id;
}
}
Run Code Online (Sandbox Code Playgroud)
package model.dao.mappings.collections.embedable;
import model.dao.mappings.BaseEntity;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Item extends BaseEntity {

@Column(name = "ITEM_NAME")
private String name;

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "ITEM_IMAGE", joinColumns = @JoinColumn(name = "ITEM_ID"))
private List<Image> images = new ArrayList<Image>();

private Item() {}

public Item(String name, List<Image> images) {
    this.name = name;
    this.images = images;
}

public List<Image> getImages() {
    return images;
}

public void setImages(List<Image> images) {
    this.images = images;
}

}
Run Code Online (Sandbox Code Playgroud)
package model.dao.mappings.collections.embedable;
import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class Image {

@Column(name = "IMAGE_TITLE")
private String title;

private ImageMetadata imageMetadata;

private Image() {}

public Image(String title, ImageMetadata imageMetadata) {
    this.title = title;
    this.imageMetadata = imageMetadata;
}
}
Run Code Online (Sandbox Code Playgroud)
package model.dao.mappings.collections.embedable;
import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class ImageMetadata {

@Column(name = "SIZE_X")
private int sizeX;

@Column(name = "SIZE_Y")
private int sizeY;

private ImageMetadata() {}

public ImageMetadata(int sizeX, int sizeY) {
    this.sizeX = sizeX;
    this.sizeY = sizeY;
}
}
Run Code Online (Sandbox Code Playgroud)
package model.dao.mappings.collections.embedable;
import model.dao.mappings.BaseEntity;
import javax.persistence.*;
import java.util.List;
@Entity
public class Photo extends BaseEntity {
private String title;

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "PHOTO_METADATA", joinColumns = @JoinColumn(name = "PHOTO_ID"))
private List<ImageMetadata> metadataList;

private Photo() {}

public Photo(String title, List<ImageMetadata> metadataList) {
    this.title = title;
    this.metadataList = metadataList;
}
}
Run Code Online (Sandbox Code Playgroud)

sen*_*eft 5

如果我添加getter/setter,问题就解决了.但是,我仍然不明白为什么我需要这样做以及为什么Photo实体映射在没有访问器的情况下工作.根据"Java Persistence with Hibernate"(作者是Hibernate开发人员)第二版"这是JPA中的规则:如果@Id在一个字段上,JPA提供者将直接访问该类的字段"The BaseEntity使用@Id on一个字段,所以访问类型是FIELD,而不是PROPERTY.我不明白为什么当访问类型是FIELD时,Hibernate不能使用反射来嵌套嵌入对象.

如果我将@Access(AccessType.FIELD)注释添加到@Embeddable ImageData,问题也会解决.

摘要

根据JPA规范

2.3.1默认访问类型

默认情况下,单个访问类型(字段或属性访问)适用于实体层次结构.实体层次结构的默认访问类型由映射注释放置在实体类的属性和未明确指定访问类型的实体层次结构的映射超类中确定.通过Access注释[6]显式指定访问类型,如2.3.2节所述

如果你使用Hibernate,它对嵌套@Embeddable类(不止一个)是行不通的.要获得正确的映射,您需要在@Embeddable类上显式指定访问类型.