7

I have my Entity:

@Entity
@Table(name="performances")
@AssociationOverrides({
    @AssociationOverride(name="id.player", joinColumns=@JoinColumn(name="player_id")),
    @AssociationOverride(name="id.season", joinColumns=@JoinColumn(name="season_id"))
})
public class Performance extends AbstractEntity<PerformanceID> {

    private static final long serialVersionUID = 1L;

    @EmbeddedId
    @Getter @Setter
    private PerformanceID id;
    @Getter @Setter
    private int goals;

    public Player getPlayer(){
        return id.getPlayer();
    }

    public Season getSeason(){
        return id.getSeason();
    }

and:

@Embeddable
public class PerformanceID implements Serializable {

    private static final long serialVersionUID = 1L;

    @ManyToOne(fetch=FetchType.LAZY, targetEntity=Player.class)
    @JoinColumn(name="player_id")
    @Getter @Setter
    private Player player;
    @ManyToOne(fetch=FetchType.LAZY, targetEntity=Season.class)
    @JoinColumn(name="season_id")
    @Getter @Setter
    private Season season;

How to select Performance records where Players have name 'Claudio' ? In HQL it simply works:

Query query = getSession().createQuery("from Performance where id.player.name = 'Claudio'");
return query.list();

But I need to do it by Criteria API. Following code will fail:

Criteria criteria = getSession().createCriteria(Performance.class);
criteria.add(Restrictions.ilike("id.player.name", "Claudio"));
return criteria.list();

org.hibernate.QueryException: could not resolve property: id.player.name of: pl.andrzejcichon.criterionlazydatamodel.entities.Performance at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:83) at org.hibernate.persister.entity.AbstractPropertyMapping.toColumns(AbstractPropertyMapping.java:98) at org.hibernate.persister.entity.BasicEntityPropertyMapping.toColumns(BasicEntityPropertyMapping.java:61) at org.hibernate.persister.entity.AbstractEntityPersister.toColumns(AbstractEntityPersister.java:1912) at org.hibernate.loader.criteria.CriteriaQueryTranslator.getColumns(CriteriaQueryTranslator.java:523) at org.hibernate.loader.criteria.CriteriaQueryTranslator.findColumns(CriteriaQueryTranslator.java:538) at org.hibernate.criterion.LikeExpression.toSqlString(LikeExpression.java:80) at org.hibernate.loader.criteria.CriteriaQueryTranslator.getWhereCondition(CriteriaQueryTranslator.java:419) at org.hibernate.loader.criteria.CriteriaJoinWalker.(CriteriaJoinWalker.java:123) at org.hibernate.loader.criteria.CriteriaJoinWalker.(CriteriaJoinWalker.java:92) at org.hibernate.loader.criteria.CriteriaLoader.(CriteriaLoader.java:93) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1599) at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:374) at pl.andrzejcichon.criterionlazydatamodel.repository.impl.PerformanceDatabaseRepository.customList(PerformanceDatabaseRepository.java:29) at pl.andrzejcichon.criterionlazydatamodel.repository.impl.PerformanceDatabaseRepositoryTest.test(PerformanceDatabaseRepositoryTest.java:24) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

The other try:

Criteria criteria = createCriteria();
criteria.createAlias("id.player", "player");
criteria.add(Restrictions.ilike("player.name", "Claudio"));
return criteria.list();

Will generate query:

Hibernate: select this_.player_id as player2_1_0_, this_.season_id as season3_1_0_, this_.goals as goals1_0_ from performances this_ where player1_.name ilike ?

But it will fail with SQLGrammarException : "Missing FROM clause for table player1_"

Ross
  • 1,313
  • 4
  • 16
  • 24
Cichy
  • 1,319
  • 3
  • 20
  • 36

1 Answers1

0

Your mapping is incorrect. An EmbeddableId class should contain @Id (thus Serializable) values, not mappings or complex types. You should move your mappings to your entity class, and then only include their id's in the EmbbedableId class. See the following example (from the JPA 2.2 specification)

@Embeddable
public class DependentId {
    String name;
    long empPK;   // corresponds to PK type of Employee
}

@Entity
public class Dependent {
    @EmbeddedId DependentId id;

    // id attribute mapped by join column default
    @MapsId("empPK") // maps empPK attribute of embedded id
    @ManyToOne Employee emp;
}
  • your example is not compatible with what you are mentioning. I dont see any @Id in the embeddable class, neither it is Serializable – Stephan Feb 24 '21 at 06:42
  • Only IDE's care about Id's being serializable these days. I was talking about the serializability of the fields. Or more important: they should be basic values. But you could add the interface to the EmbeddedID class as well if you desire ;-) The example actually comes from the JPA spec itself. – Jan-Willem Gmelig Meyling Mar 11 '21 at 21:06