简体   繁体   中英

Hibernate: How to map @ManyToOne with polymorphism (@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:

我的表结构

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM