4

I'm working on migrating some code that has two entities (Progress and PerformanceRating) that are related by a many-to-many relationship. Each PerformanceRating has multiple Progress and each Progress type can be assigned to several PerformanceRatings. Additionally, each PerformanceRating->Progress has an additional "amount" value that relates to the progress.

Current the PerformanceRating object contains a Map representing the "amount" of progress for each Progress type assigned to the PerformanceRating object.

It is coded as follows:

@Entity
class PerformanceRating{
....
....
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "performance_rating_progress_reward", joinColumns = { @JoinColumn(name = "id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "amount", nullable = false, updatable = false) })
public Map<Progress, Integer> getRewardAmountByProgressMap() {
    return this.rewardAmountByProgressMap;
}

However, when I start JBoss (with hibernate 3.6/JTA/JPA), I get the following error:

Use of @OneToMany or @ManyToMany targeting an unmapped class: fwl.domain.model.PerformanceRating.rewardAmountByProgressMap[java.lang.Integer]

I found a similar thread (Persist a Map<Integer,Float> with JPA), but that one seems to deal with non-entity types. In a case such as mine, where I am looking for an Entity/value type mapping, what is the correct syntax?

Is there a way to do this in Hibernate/JPA2?

Thanks,

Eric

2
  • JPA doesn't cater for the case of Map<Entity, Non-Entity>. JDO is the only persistence specification to handle that case Commented Sep 28, 2011 at 7:24
  • Thanks for the tip. I didn't know about JDO so I spent a little bit of time reading up on it and I find it very interesting. Had I know about that 6 months ago, I would have pushed for a JDO implementation vs a JPA one; it sounds like it has a lot of benefits. Will definitely keep it in mind for future projects. Commented Sep 28, 2011 at 19:50

1 Answer 1

2

The error you get:

Use of @OneToMany or @ManyToMany targeting an unmapped class: fwl.domain.model.PerformanceRating.rewardAmountByProgressMap[java.lang.Integer]

relates to the fact that with annotations like @OneToMany and @ManyToMany you say that the declaring class (PerformanceRating) is in a many-to-many relation with your map's value, Integer which is silly.

The value of your map should be an entity, its key should be the id with which you can identify one of those entities that your map contains (actually the key have to be only unique, I think, it needn't be an actual id).


I really don't know how your table looks like, but if your PerformanceRating (lets call it just Rating for ease's sake) looks like this:

rating
============
id               int(11) PK

and your Progress table like this:

progress
============
id               int(11) PK
amount           int(11)

with a table connecting these like this:

progress_has_rating
============
progress_id      int(11) PK
rating_id        int(11) PK

then you can map these in the following way:

@Entity @Table class Rating {
  @Id long id;
  @ManyToMany(targetEntity = Progress.class,
              cascade = CascadeType.ALL,
              fetch = FetchType.EAGER)
  @JoinTable(name = "progress_has_rating",
             joinColumns = {@JoinColumn(name = "rating_id", 
                                        referencedColumnName = "id")},
             inverseJoinColumns = {@JoinColumn(name = "progress_id",
                                               referencedColumnName = "id")})
  Set<Progress> progresses;
}

@Entity class Progress {
  @Id long id;
  @Basic long amount;
}

(It's quite possible that I switched up the column names in the @JoinColumn annotations that would actually work; I always switch 'em up.)

(Edit: yes, I've switched them—fixed.)


If your amount property is in your join table, then you'll need to create an entity class for that also. I think it isn't possible to get around that.

If you really want to use maps, then Hibernate can manage that. See the Collection mapping section (section 7.2.2.2 particularly) on how to map maps. Still, values in your map would need to be entities of some kind.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the clarification. It kind of confirmed what I had feared. I'm not happy with the structure of the code or the tables either, but I'm not tasked with that cleanup as that will be a serious undertaking. I'm just trying to clean things up without changing functionality or strcutre if at all possible to make it work, and the current mapping is obviously broken. Unfortunately, it isn't just a set that I need. The "amount" field is actually stored in the join table, and not in the progress table.
That's unfortunate, but not w/o precedent. :) However, you really cannot get around creating an entity class for to represent your join table. Check-out these links here and here, maybe they can help you some way. Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.