sunghun
sunghun

Reputation: 1424

How to handle compound key with relationship in JPA2 and Spring Data JPA?

I have a problem to handle mapping object relationship for mysql tables. I have 2 tables shown below:

Device
-----------
deviceId PK
deviceName

ApkInfo
--------
id PK
packageName
appName
deviceId FK

And then here are my classes:

@Entity
@Table(name="Device")
public class Device implements Serializable {

   @Column
   @Id
   private String deviceId;

   @Column
   private String deviceName;

   //getters and setters

}


@Entity
@Table(name="ApkInfos")
public class ApkInfo implements Serializable {

   @Column
   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   private int id;

   @Column
   @Id
   private String packageName;

   @Column
   private String appName;

   @Column
   @Temporal(TemporalType.TIMSTAMP)
   private Date installDate;

   @ManyToOne
   @JoinColumn(name="deviceId" referencedColumnName="deviceId")
   private Device device;

   //getters and setters

}

This works for me, but I want to use compound key, deviceId and packageName, in ApkInfos table.

@Entity
@Table(name="ApkInfos")
public class ApkInfo implements Serializable {

   @Colum(instable=false, updatable=false)
   @Id
   private String deviceId;

   @Column
   private String packageName;

   @Column
   private String appName;

   @ManyToOne
   @JoinColumn(name="deviceId" referencedColumnName="deviceId")
   private Device device;

   //getters and setters

}

But when I tried to save an entity using Spring Data JPA repository, I got an error:

org.springframework.dao.InvalidAccessApiUsageException: Class must not be null, nested exception is java.lang.IllegalArgumentException: Class must not be null

ApkInfo apkInfo = new ApkInfo();
apkInfo.setDeviceId("1234");
apkInfo.setPackageName("aaa");
apkInfo.setAppName("myapp");
apkInfo.setInstallDate(new Date());
apkInfo.setDevice(new Device("1234"));

repository.save(apkInfo);

And device has the deviceID '1234' already exists in the Device table.

Upvotes: 3

Views: 8435

Answers (1)

sunghun
sunghun

Reputation: 1424

I created a separate primary key class added @IdClass in the ApkInfo class. It works fine now, thanks. I am going to have a look at EmbeddedId more later.

I added @IdClass at the entity class and @Id for the packageName property. Also I made insert, update false for the One-to-many column.

@Entity
@Table(name="ApkInfos")
@IdClass(ApkInfo.class)
public class ApkInfo implements Serializable {

   @Column @Id private String deviceId;
   @Column @Id private String packageName;

   @ManyToOne
   @JoinColumn(name="deviceId" referencedColumnName="deviceId", insetable=false, updatable=false)
   private Device device;


  //getters and setters missing
}

Primary key class has only setters and overrides equals and hasCode methods.

public class ApkInfo implements Serializable {

   private String deviceId;
   private String packageName;


   public ApkInfo(){}
   public ApkInfo (String deviceId, String packageName){
       this.deviceId = deviceId;
       this.packageName = packageName;
   }

   public String getDeviceId(){
      return this.deviceId;
   }

   public String getPackageName(){
      return this.packageName;
   }

   @Override
   public boolean equals(Object obj){
      return (obj!=null && 
              obj instanceof ApkInfoPk && 
              deviceId.equals(((ApkInfoPk)obj).getDeviceId())  && 
              packageNames.equals(((ApkInfoPk)obj).getPackageName()) );
   }

   @Override
   public int hashCode(){
      super.hashCode();
   }
}

Upvotes: 6

Related Questions