开发者

How to perform the OneToMany Hibernate mapping when reverse reference is just an id attribute, not full reference

Let me be more specific, it was hard to describe this in the title.

I have a class called Bucket, which has a map to a series of Labels. The Bucket class has an id attribute. The class Label doesn't have a reference back to Bucket, instead it has a bucketId field which contains the id of the owning bucket. This was necessary to avoid circular references (Bucket to Label and back Label to Bucket) in order to allow the Bucket objects to be converted to JSON notation.

My Bucket class looks like this:

@Entity(name="Bucket")
@Table(name = "BUCKETS")
public class B开发者_开发百科ucket implements Serializable {

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

    /*
     * Map of labels indexed by the label name. I'm not sure this mapping is correct!
     */
    @ElementCollection
    @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @MapKeyColumn(name="LABEL_NAME")
    private Map<String, Label> labels = new HashMap<String, Label>();

    ...

}

and the Label class looks like this:

@Entity(name="Label")
@Table(name = "LABELS")
public class Label implements Serializable {
    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "LABEL_ID")
    protected long id;

    /*
     * How do I map this? It should point to the id of the Bucket instance that has
     * this label in its "labels" map
     */
    protected long bucketId;


    @Column(name = "LABEL_NAME", length=250, nullable=false)
    private String name;

    ...

}

If I could have a Bucket reference in the Label, I would map it as a @OneToMany and then in the Buckets class I would map as @ManyToOne(mappedBy="bucket"), but I don't have that reference, just the id pointing back.

Does anyone knows how do I map this?

Thank you! Eduardo


@ElementCollection
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
@MapKeyColumn(name="LABEL_NAME")
private Map<String, Label> labels = new HashMap<String, Label>();

First off the above mapping cannot be correct. Either use @ElementCollection OR @OneToMany, not both.

As far as the mapping of the buckedId field goes, i would just map it as a normal Long field in the Labels table. You could initialize the field with the correct bucketId, when you add a Label to a Bucket. Something like this (in the Bucket class):

public void addLabel(Label label) {
    labels.put(label.getName(), label);
    label.setBucketId(this.getId());
}

However make sure, the bucketId field in the Labels class cannot be set to an incorrect value. You could for example reduce the visibility of the setter for the bucketId field.


For some reason I am not able to comment below GeorgeG's answer, so I am responding to your second question here:

In order to set the bucketId in the Label after the Bucket has been created, you'll need to register an EventListener to do what you want to, for example (this is not necessarily working code).

    public class LabelPostInsertListener implements PostInsertListener {

        public void onPostInsert(PostInsertEvent event)
                throws HibernateException {
            Bucket bucket = (Bucket)event.getEntity();
            for (Label l : bucket.getLabels().values()) {
                l.setBucketId(bucket.getId());
            }

        }
    }

Google Hibernate EventListeners for details on configuration and the like, there are many different types, though PostInsertListener should do be right for this situation.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜