Hibernate Criteria一对多关系

3
我有两个实体: DealersMakes。 Dealers 拥有多个 Makes。我可以将记录作为这两个实体之间的一对多关系插入。
然而,我无法根据经销商 ID 检索记录。我尝试了许多不同的方法,但仍然抛出此异常:Property not found make(it is table) of : class name(full classname) 如果有人能给我提供一些提示,那将不胜感激。
Dealer:
 import java.util.HashSet;
    import java.util.Set;    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import javax.persistence.OneToMany;
    import javax.persistence.JoinTable;
    import javax.persistence.CascadeType;
    import javax.persistence.JoinColumn;
    @Entity
    @Table(name = "dealer")
    public class Dealer implements java.io.Serializable{
        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        public Dealer(){

        }
        public Dealer(String DealerName,String dealerPhno,Set makes){
            this.dealerName=DealerName;
            this.dealerphno=dealerPhno;
            this.dealerMakes=makes;

        }
        public void setDealerMakes(Set<Make> dealerMakes) {
            this.dealerMakes = dealerMakes;
        }
        @Id
        @GeneratedValue
        @Column(name = "dealer_id")
        private long dealerId;
        public long getDealerId() {
            return dealerId;
        }
        public void setDealerId(long dealerId) {
            this.dealerId = dealerId;
        }
        public String getDealerName() {
            return dealerName;
        }
        public void setDealerName(String dealerName) {
            this.dealerName = dealerName;
        }
        public String getDealerphno() {
            return dealerphno;
        }
        public void setDealerphno(String dealerphno) {
            this.dealerphno = dealerphno;
        }
        @Column(name = "dealer_name" ,unique=true, nullable = false, length=20)
        private String dealerName;
        @Column(name = "dealer_phno" , nullable = false, length=20)
        private String dealerphno;
        @OneToMany(cascade = CascadeType.ALL)
        //@OneToMany(fetch=FetchType.EAGER)
        @JoinColumn(name="dealer_id", nullable=false)
        //@JoinTable(name = "dealer_make", joinColumns = { @JoinColumn(name = "dealer_id") }, inverseJoinColumns = { @JoinColumn(name = "make_id") })
        private Set<Make> dealerMakes = new HashSet<Make>(0);

        public Set<Make> getDealerMakes() {
            return dealerMakes;
        }

    }

制作

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "make")
public class Make implements java.io.Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 2L;
    public Make(){

    }
    public Make(String makeName,String modelName,String price){

        this.makeName=makeName;
        this.modelName=modelName;
        this.price=price;
    }
    public long getMakeId() {
        return makeId;
    }
    public void setMakeId(long makeId) {
        this.makeId = makeId;
    }
    public String getMakeName() {
        return makeName;
    }
    public void setMakeName(String makeName) {
        this.makeName = makeName;
    }
    public String getModelName() {
        return modelName;
    }
    public void setModelName(String modelName) {
        this.modelName = modelName;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }
    @Id
    @GeneratedValue
    @Column(name = "make_id")
    private long makeId;
    @Column(name = "make_name" , nullable = false, length=8)
    private String makeName;
    @Column(name = "model_name" , nullable = false, length=8)
    private String modelName;
    @Column(name = "price" , nullable = false, length=8)
    private String price;

}

我尝试过的查询:

 Criteria dealer=sessionFactory.getCurrentSession().createCriteria(Dealer.class);
 Criteria make=dealer.createCriteria(make);
 make.add(Restrictions.gt("dealerId",new Long(dealerId)));
 List<Dealer> results=dealer.list(); //throwing exception

我期望的输出结果:

Dealer_Id 经销商名称 电话号码

1 halal 074563485

Make 表中有以下记录:

make_id 品牌名称 价格 经销商_id

1 ford 3000美元 1

2 hyundai 2000美元 1

我希望得到经销商和品牌详情的结果。


2
请展示您的实体和尝试过的查询。 - JB Nizet
@JB Nizet:我添加了我的实体和查询,请看一下。 - Raj
你希望这个查询做什么?它应该返回什么? - JB Nizet
@JB Nizet:我编辑了我的查询,请看一下。 - Raj
3个回答

6

好的,所以您想加载经销商及其品牌,并且您只希望经销商的ID大于给定ID。

首先,您可以仅加载经销商。当您调用getDealerMakes()时,Hibernate会自动加载它们的品牌列表:

Criteria c = session.createCriteria(Dealer.class);
c.add(Restrictions.gt("dealerId", dealerId)); // let's say delerId = 6
List<Dealer> dealers = c.list(); // execute SQL query select d.* from dealer d where d.dealer_id > 6
for (Dealer dealer : dealers) {
    Set<Make> make = dealer.getDealerMakes() // execute SQL query select m.* from make m where m.dealer_id = <theIdOfTheCurrentDealer>
}

这种方式的缺点是需要执行N + 1个查询。

如果您希望在单个查询中加载经销商及其制造商,您需要设置一个抓取模式以使制造商被加载。请注意,由于联接使用了您在Dealer和Make之间定义的关联,因此您不需要告诉Hibernate,dealer表的ID必须等于make表的dealer_id:多亏了您放在关联上的JoinColumn注释,Hibernate已经知道了。因此,查询如下:

Criteria c = session.createCriteria(Dealer.class);
c.add(Restrictions.gt("dealerId", dealerId));

// this tells Hibernate that the makes must be fetched from the database
// you must use the name of the annotated field in the Java class: dealerMakes
c.setFetchMode("dealerMakes", FetchMode.JOIN);

// Hibernate will return instances of Dealer, but it will return the same instance several times
// once per make the dealer has. To avoid this, you must use a distinct root entity transformer
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<Delaer> dealers = c.list(); // executes the SQL query:
// select d.*, m.* from dealer d left join make m on d.dealer_id = m.dealer_id where d.dealer_id > 6
for (Dealer dealer : dealers) {
    Set<Make> make = dealer.getDealerMakes() // no SQL query. The makes are already loaded
}

我不太确定这是否真的有效。假设Make有一个ManyToOne关联(比方说City),被注释为EAGER。生成的查询看起来仍然相同,但是一旦调用getDealerMakes(),就会访问DB以获取城市。对吗?至少我认为这就是我现在的经历。有没有解决方案? - T3rm1
没有解决方案。标记为EAGER的关联始终会被急切加载,无论你做什么。如果你不想每次都急切加载它,你必须将其设置为lazy-loaded。 - JB Nizet
你误解了问题。城市应该自动获取,但它们没有被获取到。我发现我遇到了这个错误:https://hibernate.onjira.com/browse/HHH-3524 - T3rm1
@JBNizet 如果我们想在经销商制造商上进行查询,并在匹配makeName时加载相关的Dealer,我们该怎么做?也可以看一下这个问题。http://stackoverflow.com/q/35867721/1766277。谢谢。 - Zahid Khan

2
criteria.setFetchMode("dealerMakes", FetchMode.JOIN);
criteria.createCriteria("dealerMakes");
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

这很管用!

1
    public List<Dealer> findDealers() {
    Criteria dealer=sessionFactory.getCurrentSession().createCriteria(Dealer.class);
    Criteria make=dealer.createCriteria(make);
    make.setFetchMode("dealer", FetchMode.JOIN);
    make.add(Restrictions.gt("dealerId",new Long(dealerId)));
    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); // depends on wat u want
    return criteria.list();
    }

尝试像这样返回,希望它能正常工作,如果还有其他问题,请告诉我。

谢谢,你代码第三行的make应该放在引号内对吧? - Raj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接