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

时间:2013-08-26 09:45:54

标签: hibernate jpa

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

异常的原因是列号与实际属性编号不匹配。

接下来是数组的内容:

columnAliases = [IMAGE_TITLE]
propertyNames = [imageMetadata,title]

-

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] );
        }
    }

}

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;
}
}

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;
}

}

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;
}
}

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;
}
}

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;
}
}

1 个答案:

答案 0 :(得分:5)

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

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

摘要

根据JPA规范

  

2.3.1默认访问类型

     

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

中所述

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