Use Map as property of model in Play

2020-05-24 05:47发布

问题:

I'm trying to use a Map as a type for one of my models properties. Let's take these two classes for example:

@Entity
public class Foo extends Model {

    @OneToMany(mappedBy = "foo", cascade = CascadeType.ALL)
    @MapKey(name = "name")
    public Map<String, Bar> bars;

    public String name;

}

@Entity
public class Bar extends Model {

    @ManyToOne
    public Foo foo;

    public String name;
}

Very simplified of course, but that's the basic idea. So what I'm trying to achieve is get a map with Bars as values and the names as their keys into Foo.

Now I want to utilize Fixture to load some data from this YAML file:

Foo(foo1):
    name: Foo1

Foo(foo2):
    name: Foo2

Bar(bar1):
    name: Bar1
    foo: foo1

Bar(bar2):
    name: Bar2
    foo: foo1

No problems so far, this works like a charm. Now if I try to change bar2 to foo: foo2, I get this Exception:

play.exceptions.JavaExecutionException: Cannot load fixture initial-data.yml: org.hibernate.HibernateException: Found two representations of same collection: models.Foo.bars
    at play.jobs.Job.call(Job.java:166)
    at Invocation.Job(Play!)
Caused by: java.lang.RuntimeException: Cannot load fixture initial-data.yml: org.hibernate.HibernateException: Found two representations of same collection: models.Foo.bars
    at play.test.Fixtures.loadModels(Fixtures.java:221)
    at jobs.Bootstrap.doJob(Bootstrap.java:18)
    at play.jobs.Job.doJobWithResult(Job.java:55)
    at play.jobs.Job.call(Job.java:157)
    ... 1 more
Caused by: javax.persistence.PersistenceException: org.hibernate.HibernateException: Found two representations of same collection: models.Foo.bars
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:798)
    at play.db.jpa.JPABase._save(JPABase.java:47)
    at play.test.Fixtures.loadModels(Fixtures.java:205)
    ... 4 more
Caused by: org.hibernate.HibernateException: Found two representations of same collection: models.Foo.bars
    at org.hibernate.engine.Collections.processReachableCollection(Collections.java:175)
    at org.hibernate.event.def.FlushVisitor.processCollection(FlushVisitor.java:60)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:122)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:83)
    at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:77)
    at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:165)
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:240)
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:795)
    ... 6 more    

at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:795)
... 6 more

Of course I tried to google it but couldn't find any solution for my case. Any ideas on that? Funnily enough, I can go and change the values in the database afterwards and assign bar2 to foo1 and it all works perfectly fine, so I can't be too wrong...

Help would be much appreciated :)

Best, kalarzo

回答1:

I tryed your code today and it worked without problems. Which play version do you use? I use 1.2.3.

Maybe the plugin association solves that problem, because that is what I'm using in background. Please let me know if an upgrade helped you.

Follows standard play module installation procedure:

play install associations

Add the following line to your dependencies.yml replacing 1.0 with desired version:

require:
    - play -> associations 1.0


回答2:

I had the same issue in v1.2.3 with Fixtures. Strangely if I didn't define a fixture below the one with the bi-directional Map OneToMany relationship there wasn't a problem. I also had a problem in one of my controllers if I didn't setup the bi-directional relationship completely. It does seem to be directly related to using a Map in a bi-directional OneToMany relationship. I switched to a Set and the problem went away. In the end I managed to resolve the situation without reverting to a Set by upgrading to v1.2.4RC2. I had a quick look through the change list in v1.2.4RC2 but couldn't spot anything that directly mentioned fixing this issue but something must have been resolved.



回答3:

Remove the:

@MapKey(name = "name")