如何正确添加记录到jpa onetomany join table

How to correctly add records to jpa onetomany join table

我正在开发一个文件系统,我有 3 个 tables。 PROJECTS table 由项目 ID、项目名称和其他详细信息组成(见下文)。这是一个现有的 class 和已填充的架构,如果可能,我不想修改应用程序的这一部分。

Folders table(称为 ProjectClassification)由 folderid 和 foldername 组成,是单向 onetomany 关系的拥有方。

Project_Folders 是一个连接 table。我使用 JPA 2.0 (EclipseLink) 和 JSF 2.0 作为我的网络框架。

我的基本问题是我无法使用合并操作将重复记录添加到联接 table。 MERGE 适用于添加记录,直到拥有的键已经存在,之后它只会更新连接 table。我知道这是它应该的工作方式,但我需要添加新记录,即使拥有密钥有副本也是如此。这将允许我将不同的项目存储在同一个文件夹中。

我在这里查看了一些其他问题,例如:

onetomany unidirectional with jointable setup using jpa

这说明在连接中将一个实体添加到另一个实体需要什么 table 但我需要了解更多有关如何正确保留或合并添加的实体到数据库的信息。

文件夹实体class:

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

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int proclassid;
private int projectid;

private String classification;

@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "PROJECT_CLASSF_JOIN",
        joinColumns = @JoinColumn(name = "proclassid", referencedColumnName = "proclassid"),
        inverseJoinColumns = @JoinColumn(name = "projectid", referencedColumnName = "projectid", unique = true))

private Collection<Projects> projects;

public ProjectClassifications() {

}

public ProjectClassifications(String classification) {
    this.classification = classification;
}

public ProjectClassifications(int proclassid, int projectid) {
    this.proclassid = proclassid;

    projects = new ArrayList<Projects>();
}

public ProjectClassifications(Projects newProject) {

    projects = new ArrayList<Projects>();

}

public void addProject(Projects newProject) {
    if(!getProjects().contains(newProject))
    getProjects().add(newProject);
}

....
....

项目实体 class 是预先存在的代码,如果可能我根本不想修改:

@Entity
@Table(name = "PROJECTS")
public class Projects {

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

private String projectName;
private String projectDescription;

@Temporal(javax.persistence.TemporalType.DATE)
private Date startDate;
@Temporal(javax.persistence.TemporalType.DATE)
private Date endDate;
private String commnts;



// foreign keys to parent tables
private int fk_countryid;
private int fk_companyid;
private int fk_employeeid;

@ManyToOne(optional = true)
@JoinColumn(name = "countryid")
private Country country;
....
....

然后我使用两个 html select 列表到 select projectid 和 proclassid 的值,它们使用 JSF 托管 bean 调用以下方法:

public String makeProClassRecord() {
   newProClass = new ProjectClassifications(proclassid, projectid);
   newProject = proServ.findByProjectId(projectid);
   newProClass.addProject(newProject);


facade.update(newProClass);
//facade.save(newProClass);
    return showProclass();
}

我的问题是:

1) MERGE 是用于将记录添加到联接中的正确操作吗 table?

2) 有没有办法使用 MERGE 添加包含重复键的记录(外键在连接 table 中表示为新记录)?

3) 是否应该使用 PERSIST 来实现问题 2?

4) 为连接 table 本身创建一个实体并简单地使用 PERSIST 方法插入记录会更好吗?

非常感谢

所以几周前我自己解决了这个问题,并想分享答案。我没有对任何目标实体进行合并或持久化操作,而是创建了一个 Join table 和从 Project 实体到下面的 ProjectFileSystem join table 实体的单向 OneToMany 关系,并使用它简单地进行了持久化操作实体。我需要为不同的项目添加重复的文件夹(或将多个项目存储在一个文件夹项下),因此在实际的 join table 实体中而不是在目标实体中执行 CRUD 操作似乎更有效。希望这会有所帮助:

@Entity
@Table(name = "PROFOLDERSYS_JOIN")

public class ProjectFileSystem implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int foldersysid;

private int proclassid;

private int projectid;

private String projectName;

private String folderName;

public ProjectFileSystem() {

}

public ProjectFileSystem(int proclassid, int projectid,
        String projectName, String folderName) {
    this.proclassid = proclassid;
    this.projectid = projectid;
    this.projectName = projectName;
    this.folderName = folderName;
}


// getters and setters
}

bean 中的方法是:

public String makeProSys() {
    newProSys = new ProjectFileSystem(proclassid, projectid,     classification, projectName);

    newProject = proServ.findByProjectId(projectid);
    projectName = newProject.getProjectName();
    newProSys.setProjectName(projectName);

    newProClass = facade.findByContactId(proclassid);
    classification = newProClass.getClassification();
    newProSys.setFolderName(classification);

    profilFacade.save(newProSys);
    return showProSys();
}