【问题标题】:Hibernate: How to map @ManyToOne with polymorphism (@ManyToAny)Hibernate:如何使用多态映射 @ManyToOne (@ManyToAny)
【发布时间】:2020-11-21 08:38:22
【问题描述】:

假设我至少有两个实体。

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

...
}

当我尝试创建进程时,会执行以下操作:

插入里程碑(id、名称、流程)值(null、?、?)

如何映射@ManyToOne 属性,即流程不是插入里程碑表而是通过与process_nodes 表连接获得的?


编辑:

我现在做了以下事情:

   @ManyToOne(fetch = FetchType.LAZY)
    @Transient
    private Process process;

我可以从里程碑访问流程,但流程未保存在里程碑表中。

有没有更简洁的方法来实现这一目标?


第二次修改

更多细节:

ProcessNode 是其他两个实体继承自的接口。使用休眠注释@ManyToAny,我将其映射到以下结构中:

【问题讨论】:

    标签: java hibernate spring-data-jpa


    【解决方案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);
                
               //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;
            }
        }
    

    更新

    根据下面的 cmets,问题是 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;
    

    【讨论】:

    • 感谢您的回答。你看到我的编辑了吗?我添加了@Transient 注释,因为我的问题是进程被插入到里程碑表中。
    • 当您说流程被插入里程碑表时,您是指process_id吗?
    • 不,id和name属于里程碑,流程列引用流程实体。但我现在明白你的问题了。所以你的问题是里程碑表应该只有两列 id 和 name 但没有 process 列。晚饭后我会很快回来找你的。它应该可以通过映射或指示它已经在连接表中来实现
    • 不幸的是它不起作用。 Process_Id 列在连接表和里程碑表中重复,如果你做瞬态,没有意义,因为它不会填充参考
    • 这不是一个大问题,因为一列重复但很烦人。但不要将其与进程记录未存储在milestone 表中相混淆。它只是 process_id 列。如果你看一下数据库中的值,就会清楚
    猜你喜欢
    • 1970-01-01
    • 2019-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 2020-07-01
    • 1970-01-01
    相关资源
    最近更新 更多