Hibernate无法使用ManyToMany映射Map集合

时间:2013-09-26 08:34:39

标签: java hibernate

在过去的4个小时里,我一直在拼命尝试进行以下制图工作。

@Entity
public class Foo {

    @Basic
    private String bar;

    @Id
    @Column(name = "FOO_ID")
    @Type(type = "foo.bar.OracleGuidType")
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    private UUID id;

    @ManyToMany(mappedBy = "parentFoos", fetch = FetchType.EAGER)
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    @MapKeyColumn(name = "NESTED_FOO_KEY")
    private Map<String, Foo> nestedFoos = new
            HashMap<String, Foo>();

    @ManyToMany
    @JoinTable(
            name = "FOO_RELATIONSHIP",
            joinColumns = @JoinColumn(name = "NESTED_FOO_ID",
                                      referencedColumnName = "FOO_ID"),
            inverseJoinColumns = @JoinColumn(name = "PARENT_FOO_ID",
                                             referencedColumnName = "FOO_ID")
    )
    private Set<Foo> parentFoos = new HashSet<Foo>();
    //getters/setters

}

映射可能很复杂,但这就是要求。

问题在于,当我尝试执行以下操作时

    Foo parent = new Foo();
    parent.setWhatever("parent");
    Foo child = new Foo();
    child.setWhatever("child");

    Session currentSession = sessionFactory.getCurrentSession();
    Transaction tx = currentSession.getTransaction();
    tx.begin();
    currentSession.saveOrUpdate(child);
    tx.commit();

    currentSession = sessionFactory.getCurrentSession();
    tx = currentSession.getTransaction();
    tx.begin();
    child.getParentFoos().add(parent);
    parent.getNestedFoos().put("ASDF_KEY", child);
    currentSession.saveOrUpdate(parent);
    tx.commit();

我得到的是:
Hibernate:插入Foo(无论如何,FOO_ID)值(?,?)
Hibernate:插入Foo(无论如何,FOO_ID)值(?,?)
Hibernate:更新Foo设置什么=?其中FOO_ID =?
Hibernate:插入FOO_RELATIONSHIP(NESTED_FOO_ID,PARENT_FOO_ID)值(?,?)

似乎hibernate忽略了mapkeycolumn(虽然它通过hbm2ddl创建了一个),接下来我得到的是这个例外

  

引起:java.sql.BatchUpdateException:ORA-01400:无法插入NULL(“BAR”。“FOO_RELATIONSHIP”。“NESTED_FOO_KEY”)

我相信,这个实体可以映射。请帮我解决这个问题。

1 个答案:

答案 0 :(得分:1)

我设法通过引入中间实体“映射”来解决问题。

这是我设法做的工作。

@Entity
@Table(name = "FOO")
public class Foo {

    @Basic
    private String bar;

    @Id
    @Column(name = "FOO_ID")
    @Type(type = "foo.bar.OracleGuidType")
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    private UUID id;

    @OneToMany(mappedBy = "parentEntity", fetch = FetchType.EAGER,
            cascade = CascadeType.ALL)
    private Set<Mapping> nestedFoos = new HashSet<>();

    @OneToMany(mappedBy = "childEntity", fetch = FetchType.EAGER,
            cascade = CascadeType.ALL)
    private Set<Mapping> parentFoos = new HashSet<>();

    @Transient
    private Map<String, Foo> _nestedFoos = new HashMap<>();

    @Transient
    private Set<Foo> _parentFoos = new HashSet<>();

    @PostLoad
    @PostUpdate
    @PostPersist
    private void fillTransientFields() {
        _nestedFoos.clear();
        _parentFoos.clear();
        for (Mapping mapping : nestedFoos) {
            _nestedFoos.put(mapping.getMappingKey(), mapping.getChildEntity());
        }
        for (Mapping mapping : parentFoos) {
            _parentFoos.add(mapping.getParentEntity());
        }
    }

    public Map<String, Foo> geNestedFoos() {
        return Collections.unmodifiableMap(_nestedFoos);
    }

    public Set<Foo> getParentFoos() {
        return Collections.unmodifiableSet(_parentFoos);
    }

    public void addParent(String key, Foo parent) {
        Mapping mapping = new Mapping();
        mapping.setMappingKey(key);
        mapping.setChildEntity(this);
        mapping.setParentEntity(parent);
        parentFoos.add(mapping);
    }

    public void addChild(String key, Foo child) {
        Mapping mapping = new Mapping();
        mapping.setMappingKey(key);
        mapping.setChildEntity(child);
        mapping.setParentEntity(this);
        nestedFoos.add(mapping);
    }

    public void removeChild(String key) {
        for (Mapping mapping : nestedFoos) {
            if (mapping.getMappingKey().equals(key)) {
                nestedFoos.remove(mapping);
            }
        }
    }
}

@Entity
@Table(name = "FOO_MAPPING_TABLE",
        uniqueConstraints = {@UniqueConstraint(columnNames =
                {"MAPPING_KEY", "PARENT_ENTITY_ID"})})
class Mapping {

    @Basic
    @Column(name = "MAPPING_KEY")
    private String mappingKey;

    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name = "ID")
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "PARENT_ENTITY_ID", nullable = false, updatable = false)
    private Foo parentEntity;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "CHILD_ENTITY_ID", nullable = false, updatable = false)
    private Foo childEntity;
}

注意,由于以下Bug

,这在Hibernate 3.6.9.Final中不起作用