Hibernate HQL join fetch not recursively fetching

后端 未结 7 584
挽巷
挽巷 2020-12-30 05:07

I have the following query and method

private static final String FIND = \"SELECT DISTINCT domain FROM Domain domain LEFT OUTER JOIN FETCH domain.operators L         


        
7条回答
  •  滥情空心
    2020-12-30 05:27

    My first observation is that you do not need to write an HQL query containing joins if your mappings say that they must be eagerly loaded.

    You can however tell the Hibernate to use fetching strategy as sub select if you don't want to use joins.

    Hibernate generates the SQL query for loading the objects during startup based on the specified mappings and caches it. However in your case, you have one to many nested relation with self and arbitrary depth, so looks like it won't be possible for hibernate to decide before hand the sql to correctly eager fetch. So it would need to send multiple joins queries depending upon the depth of the parent Domain you are querying at runtime.

    To me it looks like you are thinking that HQL and the resulting SQL/('s) in your case can have one to one correpondence which is not true. With HQL you query for objects and the orm decides how to load that object and its relations (eager/lazy) based on the mappings or you can specify them at runtime too ( for e.g, a lazy association in mapping can be overridden by Query api but not vice versa). You can tell the orm what to load ( my marking eager or lazy ) and how to load eagerly ( either using join / sub select).

    UPDATE

    When I run the following query on your domain model

    SELECT DISTINCT domain FROM Domain domain LEFT OUTER JOIN FETCH domain.operators LEFT OUTER JOIN FETCH domain.networkCodes WHERE domain.domainId = :domainId";
    

    I can see that the networkCode and operator collections are of instance PersistentSet ( this is Hibernate wrapper) and both have initialized property set to be true. Also in the underlying session context I can see the domains with the domain and the operators listed. So what is making you think that they are not eagerly loaded ?

    This is how my domain looks like

    @Entity
    @Table
    public class Domain {
        @Id
        @GenericGenerator(name = "generator", strategy = "increment")
        @GeneratedValue(generator = "generator")
        @Column(name = "domain_id")
        private Long domainId;
    
        @Column(nullable = false, unique = true)   
        private String name;
    
        @Column(nullable = false)    
        @Enumerated(EnumType.STRING)
        private DomainType type;
    
        @OneToMany(mappedBy = "domain",cascade = {
                CascadeType.PERSIST,
                CascadeType.MERGE
        }, fetch = FetchType.EAGER)   
        private Set networkCodes = new HashSet();
    
        @ManyToMany(mappedBy="parent",fetch = FetchType.EAGER, cascade=CascadeType.ALL)
        private Set operators = new HashSet();
        // more
    
        @ManyToOne  
        private Domain parent;
    
        public String getName() {
            return name;
        }
    
    
        public void setName(String name) {
            this.name = name;
        }
    
    
    public DomainType getType() {
            return type;
        }
    
        public void setType(DomainType type) {
            this.type = type;
        }
    
    
        public Set getOperators() {
            return operators;
        }
    
    
        public Long getDomainId() {
            return domainId;
        }
    
    
        public void setDomainId(Long domainId) {
            this.domainId = domainId;
        }
    
    
        public void setOperators(Set operators) {
            this.operators = operators;
        }
    
        public void addDomain(Domain domain){
            getOperators().add(domain);
            domain.setParent(this);
        }
    
    
        public Domain getParent() {
            return parent;
        }
    
    
        public void setParent(Domain parent) {
            this.parent = parent;
        }
    
        public void addNetworkCode(NetworkCode netWorkCode){
            getNetworkCodes().add(netWorkCode);
            netWorkCode.setDomain(this);
        }
    

    enter image description here

提交回复
热议问题