0

Let's say I have 2 entities: Application and Organization. They are many-to-many related

Organization:

@Entity
@Table(name = "organizations")
public class Organization
{

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "organizationIdGenerator")
    private long id;  // primary key

    @AttributeOverride(name = "id", column = @Column(name = "organization_id", unique = true, updatable = false))
    @Embedded
    private OrganizationId organizationId;

    @AttributeOverride(name = "id", column = @Column(name = "application_id"))
    @CollectionTable(name = "organization_applications")
    @ElementCollection
    private Set<ApplicationId> applications = new HashSet<>();  // there is no explicit @Many-to-many connection between applications and organizations

    private String name;

    // other data
}

Application:

@Entity
@Table(name = "applications")
public class Application
{

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "applicationIdGenerator")
    private long id; // primary key

    @AttributeOverride(name = "id", column = @Column(name = "application_id", unique = true, updatable = false))
    @Embedded
    private ApplicationId applicationId;

    private String label;

    // other data 
}

As they are many-to-many related, in relational database I have the following tables:

  • organizations
  • applications
  • organization_applications

table organization_applications is created with the following liquibase-migration:

<createTable tableName="organization_applications">
  <column name="organization_id" type="bigint">
    <constraints nullable="false" foreignKeyName="organization_application_organization_id_fk"
                 referencedTableName="organizations" referencedColumnNames="id"/>
  </column>
  <column name="application_id" type="varchar(50)">
    <constraints nullable="false"/>
  </column>
</createTable>

What I want to do is get Applications (List<Application>) for particular Organization in one query


I can do it by getting applicationIds of particular organization (lets say with organizationId = 1) and join them with applications with a query like:

select apps.application_id, apps.label 
    from organization_applications org_apps
    join applications apps 
        on (apps.application_id = org_apps.application_id and org_apps.organization_id = 1)

But when I try to accomplish this with JPQL query like this:

SELECT new List(o.applications) FROM Organization o WHERE o.organizationId.id = 1

I get the following query and then and exception:

Hibernate: 
    /* SELECT
        new List(o.applications) 
    FROM
        Organization o 
    WHERE
        o.organizationId.id = :org_id */ select
            . as col_0_0_          // <-- problem here. why is there just a dot?
        from
            organizations organizati0_ 
        inner join
            organization_applications applicatio1_ 
                on organizati0_.id=applicatio1_.organization_id 
        where
            organizati0_.organization_id=?

SqlExceptionHelper   : SQL Error: 20000, SQLState: 42X01
SqlExceptionHelper   : Syntax error: Encountered "." at line 1, column 102.

Seems that in a relation like this where entities are related by custom id fields (applicationId, organiationId) hibernate cannot create query.

Any idea how can I accomplish this?

Thanks in advance!


UPD:

ApplicationId holds some validation and looks like this:

public class ApplicationId
{
    private String id;

    // constructor and getters
}

OrganizationId looks exactly the same

Random Guy
  • 962
  • 15
  • 26
  • You haven't defined an actual *relationship* between the 2 entities you quote. You simply have a Set of some embedded object that is not defined. That is not a M-N relation –  Aug 17 '18 at 07:38
  • And new List is not possible in a query. What are you trying to achieve? – Simon Martinelli Aug 17 '18 at 09:19
  • @BillyFrost I added a migration that creates a table that defines their relation, and since `organization` is not an owner in this relation, there is no explicitly defined relation (via `@ManyToMany`) – Random Guy Aug 17 '18 at 10:52
  • @SimonMartinelli, I am trying to get *list of applications that belong to particular organization*. Since JPQL requires a DTO that is going to be populated by result values and since I am trying to get list of applications, what type should I use? Also, `select new List(...)` works perfect if I require an attribute that is `One-to-Many` related (for example, organization's phone numbers). Take a look at [this answer](https://stackoverflow.com/a/4028340/4504720) – Random Guy Aug 17 '18 at 11:04
  • Try SELECT o.applications FROM Organization o WHERE o.organizationId.id = 1 and have a look what type you will find in the result list. – Simon Martinelli Aug 17 '18 at 11:07
  • @SimonMartinelli, well, it requires an explicitly defined type and it does not conform `Object`. Error message looks like this: `org.hibernate.QueryException: not an entity [SELECT o.applications FROM com.rg.organization.Organization o WHERE o.organizationId.id = 1]` – Random Guy Aug 17 '18 at 12:48
  • how does the class ApplicationId look like? – Simon Martinelli Aug 17 '18 at 13:01
  • @SimonMartinelli, It is a simple DTO for real id represented as String. I have updated question – Random Guy Aug 17 '18 at 13:10
  • Represent it as a true JPA relation and then it is simple. Hack this sort of crap and you make your head hurt –  Aug 17 '18 at 15:27

2 Answers2

1
@Query("SELECT a FROM Application a WHERE a.applicationId IN " +
        "(SELECT apps FROM Organization o JOIN o.applications apps WHERE o.organizationId = :organization_id) ORDER BY label ASC")
0

You can select the ApplicationIds like this:

SELECT a FROM Organization o JOIN o.applications a WHERE o.organizationId.id = 1
Simon Martinelli
  • 21,335
  • 3
  • 26
  • 53
  • Looks like this query returns list of `ApplicationId`s (rather than `Application`s) when i execute it like this: `Query q = this.entityManager.createQuery("SELECT a FROM Organization o JOIN o.applications a WHERE o.organizationId.id = :org_id"); q.setParameter("org_id", "1"); List resultList = (List) q.getResultList();` Actual join does not happen and I wonder why since hibernate produces query with join: `... inner join organization_applications applicatio1_ on organizati0_.id=applicatio1_.organization_id ...` – Random Guy Aug 17 '18 at 13:27
  • I'm confused. What do you want as return type? – Simon Martinelli Aug 17 '18 at 13:44
  • I want to get a list of applications (`List`). Because getting list of `ApplicationId`s would require an extra query (to get `Application`s by `ApplicationId`s). So I have to join with table `applications` somehow. And I am struggling to create a JPQL query for this. Sorry if my explanations confused you :) – Random Guy Aug 17 '18 at 14:15