2013-05-06 2 views
2

У меня есть проблема с обработкой отношения сопоставления объектов для таблиц mysql. У меня есть 2 таблицы, как показано ниже:Как обрабатывать составной ключ с отношениями в JPA2 и Spring Data JPA?

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

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

А потом вот мои классы:

@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 

} 

Это работает для меня, но я хочу использовать соединение ключ, deviceId и packageName, в ApkInfos таблице.

@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 

} 

Но когда я попытался сохранить объект, используя Spring Data JPA хранилище, я получил сообщение об ошибке:

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); 

И устройство имеет deviceID «1234» уже существует в таблице устройств ,

+0

Вы можете найти объяснение здесь о составном ключе: http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#d0e2177 – Alex

+0

Я прочитал его, но до сих пор не ясно мне. – sunghun

+0

Создайте отдельный класс для вашего составного идентификатора (он будет вашим основным ключом), а затем используйте его с аннотацией «@EmbeddedId» в вашем основном классе вместо «@Id». – Alex

ответ

5

Я создал отдельный класс первичного ключа, добавленный @IdClass в классе ApkInfo. Спасибо, спасибо. Я еще раз посмотрю на EmbeddedId.

Я добавил @IdClass в классе сущности и @Id для свойства packageName. Также я сделал insert, update false для столбца One-to-many.

@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 
} 

Основной класс ключей имеет только сеттеры и переопределения равные и hasCode методы.

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(); 
    } 
}