openjpa:多列有额外列

时间:2012-03-04 19:42:53

标签: many-to-many hsqldb openjpa

我需要在JPA中使用额外列创建多对多的连接表。

我正在使用:openjpa-maven-plugin用于在构建期间进行增强,openjpa 2.2.0hsql file db,testng + spring

我有三个表:AnalysislocalizedAnalysisName(加入表)和Locale

我的代码:

@Entity 
@Table(name = "analysis", catalog = "testdb") 
public class Analysis { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "analysis_id", unique = true, nullable = false) 
    private int analysisId; 

    @OneToMany(mappedBy = "analysis", cascade = CascadeType.PERSIST) 
    private List<LocalizedAnalysisName> localizedNames = new ArrayList<LocalizedAnalysisName>(); 

 public void addLocalizedName(Locale locale, String localized_text) { 
        LocalizedAnalysisName localizedAnalysisName = new LocalizedAnalysisName(); 
        localizedAnalysisName.setLocale(locale); 
        localizedAnalysisName.setAnalysis(Analysis.this); 
        localizedAnalysisName.setLocaleId(locale.getLocaleId()); 
        localizedAnalysisName.setAnalysisId(this.getAnalysisId()); 
        localizedAnalysisName.setLocalizedText(localized_text); 

        localizedNames.add(localizedAnalysisName); 

    } 
    ... 


@Entity
@Table(name = "locale", catalog = "testdb")
public class Locale implements Serializable {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "locale_id", unique = true, nullable = false)
    private int localeId;
    @Column(name = "language", length = 200)
    private String language;
    @Column(name = "country", length = 200)
    private String country;
    @Column(name = "variant", length = 200)
    private String variant;

... 

@Entity
@Table(name = "localized_analysis_name", catalog = "testdb")
@IdClass(LocalizedAnalysisNameId.class)
public class LocalizedAnalysisName implements Serializable {
    @Id
    private int analysis_id;
    @Id
    private int locale_id;

    @Column(name = "localized_text", nullable = false, length = 200)
    private String localizedText;

    @ManyToOne
    @PrimaryKeyJoinColumn(name="locale_id", referencedColumnName="locale_id")
    private Locale locale;

    @ManyToOne
    @PrimaryKeyJoinColumn(name="analysis_id", referencedColumnName="analysis_id")
    private Analysis analysis;

    public LocalizedAnalysisName() {
    }

    public String getLocalizedText() {
        return localizedText;
    }

    public void setLocalizedText(String localizedText) {
        this.localizedText = localizedText;
    }

    public Locale getLocale() {
        return locale;
    }

    public Analysis getAnalysis() {
        return analysis;
    }

    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    public void setAnalysis(Analysis analysis) {
        this.analysis = analysis;
    }

    public void setAnalysisId(int analysis_id) {
        this.analysis_id = analysis_id;
    }

    public void setLocaleId(int locale_id) {
        this.locale_id = locale_id;
    }


@Embeddable
public class LocalizedAnalysisNameId implements Serializable {
    private int analysis_id;
    private int locale_id;

    public LocalizedAnalysisNameId() {
    }

    public int getAnalysisId() {
        return analysis_id;
    }

    public void setAnalysisId(int analysis_id) {
        this.analysis_id = analysis_id;
    }

    public int getLocaleId() {
        return locale_id;
    }

    public void setLocaleId(int locale_id) {
        this.locale_id = locale_id;
    }

    public int hashCode() {
        return analysis_id + locale_id;
    }

    public boolean equals(Object object) {
        if (object instanceof LocalizedAnalysisNameId) {
            LocalizedAnalysisNameId otherId = (LocalizedAnalysisNameId) object;
            return (otherId.analysis_id == this.analysis_id) && (otherId.locale_id == this.locale_id);
        }
        return false;
    }

DB:

CREATE  TABLE locale (
  locale_id integer  NOT NULL IDENTITY,
  language varchar(200) DEFAULT NULL,
  country varchar(200) DEFAULT NULL,
  variant varchar(200) DEFAULT NULL,
  PRIMARY KEY (locale_id)
  );

CREATE TABLE  analysis (
  analysis_id integer NOT NULL IDENTITY,
  source_id varchar(500) DEFAULT NULL,
  locale_id integer,
  PRIMARY KEY (analysis_id),
  FOREIGN KEY (locale_id)
  REFERENCES locale (locale_id)
);


CREATE  TABLE localized_analysis_name (
  analysis_id integer,
  locale_id integer,
  localized_text varchar(200) DEFAULT NULL,
  PRIMARY KEY (analysis_id, locale_id),
  FOREIGN KEY (analysis_id)
  REFERENCES analysis (analysis_id),
   FOREIGN KEY (locale_id)
  REFERENCES locale (locale_id)
  );

INSERT INTO LOCALE VALUES(0,'en','US','');
INSERT INTO LOCALE VALUES(1,'de','DE','');

这是我在testng中的测试方法片段:

@Test(enabled = true) 
    @Rollback(false) 
    public void testSave() { 

        Analysis analysis = new Analysis(); 

        Locale locale = localeDao.findById(0); 

        analysis.addLocalizedName(locale,"localized text"); 

        analysisDao.save(analysis); 

    } 

构建时,测试失败

invalidstateexception:  
Caused by: <openjpa-2.2.0-r422266:1244990 fatal user error> org.apache.openjpa.persistence.InvalidStateException:  
Attempt to set column "localized_analysis_name.analysis_id" to two different values: (class java.lang.Long)"0", (class java.lang.Integer)"40"  

This can occur when you fail to set both sides of a
two-sided relation between objects, or when you map
different fields to the same column, but you do not
keep the values of these fields in synch.

请问有谁可以告诉我如何以正确的方式做到这一点? 谢谢。

1 个答案:

答案 0 :(得分:1)

不要在LocalizedAnalysisName表中设置ID和键引用。您 将它们设置为不同的值:

// The test:
Analysis analysis = new Analysis(); 
Locale locale = localeDao.findById(0); 
analysis.addLocalizedName(locale,"localized text"); 

// The entity:
localizedAnalysisName.setLocale(locale); 
localizedAnalysisName.setAnalysis(Analysis.this); 
localizedAnalysisName.setLocaleId(locale.getLocaleId()); 
localizedAnalysisName.setAnalysisId(this.getAnalysisId()); 

当你调用setAnalysisId(...)时,它处于“new”状态,它还没有id(默认为0)。同时,在L.A.N.上设置Analysis实体,实体管理器将为其分配新的ID。因此,L.A.N。同时有Analysis条记录的2个不同ID。

在旁注中,@Embeddable上的LocalizedAnalysisNameId注释不是必需的,因为您不将其用作@EmbeddedId,而是直接列出其字段。