Hibernate:如何使用多态映射 @ManyToOne(@ManyToAny)

huangapple go评论84阅读模式
英文:

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,我将其映射到以下结构中:

Hibernate:如何使用多态映射 @ManyToOne(@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 = &quot;node_type&quot;),
fetch = FetchType.LAZY
)
@AnyMetaDef(
idType = &quot;long&quot;, metaType = &quot;string&quot;,
metaValues = {
@MetaValue(targetEntity = Milestone.class, value = MILESTONE_DISC),
@MetaValue(targetEntity = Phase.class, value = PHASE_DISC)
}
)
@Cascade({org.hibernate.annotations.CascadeType.ALL})
@JoinTable(
name = &quot;process_nodes&quot;,
joinColumns = @JoinColumn(name = &quot;process_id&quot;, nullable = false),
inverseJoinColumns = @JoinColumn(name = &quot;node_id&quot;, nullable = false)
)
private Collection&lt;ProcessNode&gt; nodes = new ArrayList&lt;&gt;();
...
}

@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&lt;ResultDefinition&gt; 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:

Hibernate:如何使用多态映射 @ManyToOne(@ManyToAny)

答案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(&quot;process-1&quot;);
Milestone milestoneOne = new Milestone();
milestoneOne.setProcess(process);
milestoneOne.setName(&quot;milestone-1&quot;);
Milestone milestoneTwo = new Milestone();
milestoneTwo.setProcess(process);
milestoneTwo.setName(&quot;milestone-2&quot;);
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&lt;Process&gt; findAll(){
List&lt;Process&gt; processes = processRepository.findAll();
processes.forEach(System.out::println);
//This prints the following
// Process{id=1, name=&#39;process-1&#39;,
// nodes=[Milestone{id=1, name=&#39;milestone-1&#39;},
//        Milestone{id=2, name=&#39;milestone-2&#39;}]}
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 = &quot;process_nodes&quot;,
joinColumns = @JoinColumn(name = &quot;process_id&quot;, 
nullable = false, 
insertable = false, 
updatable = false),
inverseJoinColumns = @JoinColumn(name = &quot;node_id&quot;, 
nullable = false, 
insertable = false, 
updatable = false)
)
@WhereJoinTable(clause = &quot;node_type=&#39;milestone&#39;&quot;)
private Process process;

huangapple
  • 本文由 发表于 2020年7月31日 21:30:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/63192842.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定