malificent
malificent

Reputation: 1441

JPA annotate composite primary key that is also a one to many foreign key

Been working on this for a couple of days and haven't yet seen an example that matches what I'm trying to do or I'm missing it as I'm a bit new to Hibernate and JPA. I'm attempting to convert some hibernate code over to JPA and can't seem to get a particular join correct.

Here is my table structure:

Table AppUser

  • id (PK)

Table SecurityQuestion

  • id (PK)

Table AppUserSecurityQuestion

  • AppUserId (PK, FK to AppUser.id)

  • SecurityQuestionId (PK, FK to SecurityQuestion.id)

And here is what I've tried to far with my domains (just relevant property declarations):

BaseEntity.java

@MappedSuperclass
public abstract class BaseEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id", updatable=false, nullable=false)
    private Integer id;
    ...
}

AppUser.java

@Entity
@Table(name="AppUser")
public class AppUser extends BaseEntity {
    @OneToMany(fetch=FetchType.EAGER)
    @MapKeyJoinColumn(name="AppUserId")
    private Set<AppUserSecurityQuestion> securityAnswers;
    ...
}

AppUserSecurityQuestion.java

@Entity
@Table(name="AppUserSecurityQuestion")
public class AppUserSecurityQuestion implements java.io.Serializable {
    @EmbeddedId
    private AppUserSecurityQuestionId id;
    ...
}

AppUserSecurityQuestionId.java

@Embeddable
public class AppUserSecurityQuestionId implements java.io.Serializable {
    private AppUser appUser;
    private SecurityQuestion securityQuestion;
    ...
}

This was working with hibernate configuration but again I'm attempting to convert it over to JPA. Here are the relevant pieces of the hbm files:

AppUser.hbm.xml

<hibernate-mapping default-access="field">
    <class catalog="WEBR" name="testapp.domain.AppUser" schema="dbo" table="AppUser">
        <id name="appUserId" type="java.lang.Integer">
            <column name="AppUserId" />
            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
                <param name="sequence_name">AppUserSeq</param>
            </generator>
        </id>
        ...
        <set name="securityAnswers" table="AppUserSecurityQuestion" inverse="true" lazy="false">
            <key column="AppUserId" not-null="true" />
            <one-to-many class="testapp.domain.AppUserSecurityQuestion" />
        </set>


    </class>
</hibernate-mapping>

AppUserSecurityQuestion.hbm.xml

<hibernate-mapping>
    <class name="testapp.domain.AppUserSecurityQuestion" table="AppUserSecurityQuestion" schema="dbo" catalog="TEST">
        <composite-id name="id" class="testapp.domain.AppUserSecurityQuestionId">
            <key-many-to-one name="appUser" class="testapp.domain.AppUser">
                <column name="id"/>
            </key-many-to-one>
            <key-many-to-one name="securityQuestion" class="testapp.domain.SecurityQuestion">
                <column name="SecurityQuestionId" />
            </key-many-to-one>
        </composite-id>
        <property name="answer" type="java.lang.String">
            <column name="Answer" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

I'm basically just trying to look at the hbm's and convert each piece over to JPA but I'm apparently missing something as I get this exception when I try to access data through the application:

org.hibernate.exception.SQLGrammarException: could not extract ResultSet ... Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Invalid object name 'AppUser_AppUserSecurityQuestion'

Here is the HQL as well:

select securityan0_.AppUser_id as AppUser_1_0_0_, securityan0_.securityAnswers_appUser as security2_3_0_, securityan0_.securityAnswers_securityQuestion as security3_3_0_, appusersec1_.appUser as appUser1_2_1_, appusersec1_.securityQuestion as security2_2_1_, appusersec1_.Answer as Answer3_2_1_ from AppUser_AppUserSecurityQuestion securityan0_ inner join AppUserSecurityQuestion appusersec1_ on securityan0_.securityAnswers_appUser=appusersec1_.appUser and securityan0_.securityAnswers_securityQuestion=appusersec1_.securityQuestion where securityan0_.AppUser_id=?

I've obviously got my joins declared incorrectly but I'm not sure what else to try at this point. Anybody see what I'm doing wrong?

Upvotes: 1

Views: 2561

Answers (1)

malificent
malificent

Reputation: 1441

Figured it out...At least it appears to be working the way I need it to. Here are the changes I needed to make:

AppUser.java

@Entity
@Table(name="AppUser")
public class AppUser extends BaseEntity {
    @OneToMany(mappedBy="id.appUser", fetch=FetchType.EAGER)
    @MapKeyJoinColumn(name="id")
    private Set<AppUserSecurityQuestion> securityAnswers;
    ...
}

AppUserSecurityQuestionId.java

@Embeddable
public class AppUserSecurityQuestionId implements java.io.Serializable {
    @ManyToOne
    @JoinColumn(name="AppUserId")
    private AppUser appUser;
    @ManyToOne
    @JoinColumn(name="SecurityQuestionId")
    private SecurityQuestion securityQuestion;
    ...
}

Everything else remained as is.

Upvotes: 1

Related Questions