英文:
Hibernate: How to map @ManyToOne with polymorphism (@ManyToAny)
问题
以下是您要翻译的内容:
说我至少有两个实体。
@Entity
public class Process {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String name;
@ManyToAny(
metaColumn = @Column(name = "node_type"),
fetch = FetchType.LAZY
)
@AnyMetaDef(
idType = "long", metaType = "string",
metaValues = {
@MetaValue(targetEntity = Milestone.class, value = MILESTONE_DISC),
@MetaValue(targetEntity = Phase.class, value = PHASE_DISC)
}
)
@Cascade({org.hibernate.annotations.CascadeType.ALL})
@JoinTable(
name = "process_nodes",
joinColumns = @JoinColumn(name = "process_id", nullable = false),
inverseJoinColumns = @JoinColumn(name = "node_id", nullable = false)
)
private Collection<ProcessNode> nodes = new ArrayList<>();
...
}
@Entity
@ToString
@DiscriminatorValue(MILESTONE_DISC)
public class Milestone implements ProcessNode {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Collection<ResultDefinition> results;
@ManyToOne()
private Process process;
...
}
当我尝试创建一个Process时,会执行以下操作:
insert into milestone (id, name, process) values (null, ?, ?)
如何映射@ManyToOne属性,以便将process不插入milestone表,而是通过与process_nodes表进行连接而获取?
编辑:
我现在做了以下更改:
@ManyToOne(fetch = FetchType.LAZY)
@Transient
private Process process;
我可以从milestone中访问process,并且process不会保存在milestone表中。
有没有更清晰的方法来实现这一点?
第二次编辑
更多细节:
ProcessNode是一个接口,有两个其他实体继承自它。使用hibernate注解@ManyToAny,我将其映射到以下结构中:
英文:
Say I have at least two entities.
@Entity
public class Process {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String name;
@ManyToAny(
metaColumn = @Column(name = "node_type"),
fetch = FetchType.LAZY
)
@AnyMetaDef(
idType = "long", metaType = "string",
metaValues = {
@MetaValue(targetEntity = Milestone.class, value = MILESTONE_DISC),
@MetaValue(targetEntity = Phase.class, value = PHASE_DISC)
}
)
@Cascade({org.hibernate.annotations.CascadeType.ALL})
@JoinTable(
name = "process_nodes",
joinColumns = @JoinColumn(name = "process_id", nullable = false),
inverseJoinColumns = @JoinColumn(name = "node_id", nullable = false)
)
private Collection<ProcessNode> nodes = new ArrayList<>();
...
}
@Entity
@ToString
@DiscriminatorValue(MILESTONE_DISC)
public class Milestone implements ProcessNode {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Collection<ResultDefinition> results;
@ManyToOne()
private Process process;
...
}
When I try to create a Process the following is executed:
> insert into milestone (id, name, process) values (null, ?, ?)
How do I map the @ManyToOne property, that the the process is not inserted into the milestone table but is obtained by joining with the process_nodes table?
Edit:
I now did the following:
@ManyToOne(fetch = FetchType.LAZY)
@Transient
private Process process;
I can access the process from the milestone and the process is not saved in the milestone table.
Is there a cleaner way to achieve that?
second edit
More details:
ProcessNode is an interface where two other entities inherit from. With hibernate annotations @ManyToAny I got it to map it into the following structure:
答案1
得分: 1
以下是您提供的代码部分的翻译:
不管怎样,这里有一个使用您的类的工作解决方案,它们按预期工作。
@SpringBootApplication
public class AccessingDataJpaApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context
= SpringApplication.run(AccessingDataJpaApplication.class);
ProcessService processService
= context.getBean(ProcessService.class);
Process process = new Process();
process.setName("process-1");
Milestone milestoneOne = new Milestone();
milestoneOne.setProcess(process);
milestoneOne.setName("milestone-1");
Milestone milestoneTwo = new Milestone();
milestoneTwo.setProcess(process);
milestoneTwo.setName("milestone-2");
process.setNodes(Arrays.asList(milestoneOne, milestoneTwo));
processService.save(process);
processService.findAll();
}
}
@Service
@Transactional
public class ProcessService {
@Autowired
ProcessRepository processRepository;
public Process save(Process process){
return processRepository.save(process);
}
public List<Process> findAll(){
List<Process> processes = processRepository.findAll();
processes.forEach(System.out::println);
//这会打印以下内容
// Process{id=1, name='process-1',
// nodes=[Milestone{id=1, name='milestone-1'},
// Milestone{id=2, name='milestone-2'}]}
return processes;
}
}
更新
根据下面的评论,问题是 process_id
列在 process_nodes
连接表和 milestone
表中都重复出现。我希望使用以下方法避免在 milestone
表中出现 process_id
列,但这也不起作用:
@ManyToOne
@JoinTable(
name = "process_nodes",
joinColumns = @JoinColumn(name = "process_id",
nullable = false,
insertable = false,
updatable = false),
inverseJoinColumns = @JoinColumn(name = "node_id",
nullable = false,
insertable = false,
updatable = false)
)
@WhereJoinTable(clause = "node_type='milestone'")
private Process process;
英文:
Anyway here is working solution using your classes and they work as expected.
@SpringBootApplication
public class AccessingDataJpaApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context
= SpringApplication.run(AccessingDataJpaApplication.class);
ProcessService processService
= context.getBean(ProcessService.class);
Process process = new Process();
process.setName("process-1");
Milestone milestoneOne = new Milestone();
milestoneOne.setProcess(process);
milestoneOne.setName("milestone-1");
Milestone milestoneTwo = new Milestone();
milestoneTwo.setProcess(process);
milestoneTwo.setName("milestone-2");
process.setNodes(Arrays.asList(milestoneOne, milestoneTwo));
processService.save(process);
processService.findAll();
}
}
@Service
@Transactional
public class ProcessService {
@Autowired
ProcessRepository processRepository;
public Process save(Process process){
return processRepository.save(process);
}
public List<Process> findAll(){
List<Process> processes = processRepository.findAll();
processes.forEach(System.out::println);
//This prints the following
// Process{id=1, name='process-1',
// nodes=[Milestone{id=1, name='milestone-1'},
// Milestone{id=2, name='milestone-2'}]}
return processes;
}
}
Update
As per the comments below, the issue is process_id
column is repeated in process_nodes
join table and as well as in milestone
table. I was hoping to make use of the following to avoid the process_id
column in milestone
table as below but that does not work either
@ManyToOne
@JoinTable(
name = "process_nodes",
joinColumns = @JoinColumn(name = "process_id",
nullable = false,
insertable = false,
updatable = false),
inverseJoinColumns = @JoinColumn(name = "node_id",
nullable = false,
insertable = false,
updatable = false)
)
@WhereJoinTable(clause = "node_type='milestone'")
private Process process;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论