Hibernate多对多关系返回空集合

时间:2016-12-07 18:48:15

标签: java hibernate jpa

我在Spring Boot应用程序中添加了两个实体之间的多对多关系。我有以下映射:

Business.java:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "business_vendor",
        joinColumns = @JoinColumn(name = "business_id"),
        inverseJoinColumns = @JoinColumn(name = "vendor_id"))
@JSON(include = false)
protected List<Vendor> vendors;

Vendor.java

@ManyToMany(cascade = CascadeType.ALL, mappedBy = "vendors")
@JSON(include = false)
protected List<Business> businesses;

我可以将商家添加到商家,然后将其保存到数据库中。但是,当(在新请求中)我加载业务然后调用business.getVendors()时,我得到一个空列表。我可以从应用程序日志中看到Hibernate从链接表中选择,如果我手动对数据库运行Hibernate生成的查询,我会看到我想要的一行。我已经尝试将FetchMode切换为eager并尝试删除CascadeType.ALL,这两者都没有帮助。

此应用程序在Hibernate 4.3.11上(由于“原因”,此时无法升级)。

编辑:这是一个最小的例子:

public List<Vendor> getVendorsForBusiness(UUID businessId) {
    Business business = businessRepository.findOne(businessId.toString());
    return business.getVendors();
}

我希望这会返回一个包含1个供应商的List,但是我得到一个空列表,即使数据库中的链接表中有一行。

编辑2:这是我正在使用的持久化方法的相关部分,它在business_vendor表中成功创建了一行:

public void addVendorToBusiness(UUID businessId, UUID vendorId) {
    Vendor vendor = vendorRepository.findOne(vendorId.toString());
    Business business = businessRepository.findOne(businessId.toString());
    business.getVendors().add(vendor);
    vendor.getBusinesses().add(business); // This line doesn't make a difference
    businessRepository.save(business);
}

3 个答案:

答案 0 :(得分:0)

只需使用双向策略即可。像这样:

Business.java

@Entity
@Table(name = "BUSINESS")
public class Business implements Serializable {

    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "business_vendor",
            joinColumns = @JoinColumn(name = "business_id"),
            inverseJoinColumns = @JoinColumn(name = "vendor_id"))
//@JSON(include = false)
    private List<Vendor> vendors;

    public Business() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List<Vendor> getVendors() {
        return vendors;
    }

    public void setVendors(List<Vendor> vendors) {
        this.vendors = vendors;
    }
}

Vendor.java

@Entity
@Table(name = "VENDOR")
public class Vendor implements Serializable {

    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @ManyToMany(cascade = CascadeType.ALL, mappedBy = "vendors", fetch = FetchType.EAGER)
//    @JSON(include = false)
    private List<Business> businesses;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List<Business> getBusinesses() {
        return businesses;
    }

    public void setBusinesses(List<Business> businesses) {
        this.businesses = businesses;
    }

    public Vendor() {
    }
}

Main.java

public class Main {

    private static final SessionFactory SESSION_FACTORY = new AnnotationConfiguration().configure().buildSessionFactory();
    private Session session;
    private Transaction transaction;

    public static void main(String[] args) {

        Main main = new Main();
        main.save();
        List<Vendor> vList = main.getVendorFromBusinessId(2L);
        main.displayVendors(vList);

        SESSION_FACTORY.close();
        System.exit(0);
    }

    private void save() {

        this.session = SESSION_FACTORY.openSession();
        this.transaction = null;
        try {

            this.transaction = this.session.beginTransaction();
            Business b1 = new Business();
            Business b2 = new Business();
            Business b3 = new Business();

            Vendor v1 = new Vendor();
            Vendor v2 = new Vendor();

            List<Business> bList = new ArrayList<>();
            bList.add(b1);
            bList.add(b2);
            bList.add(b3);

            List<Vendor> vList = new ArrayList<>();
            vList.add(v1);
            vList.add(v2);

            b1.setVendors(vList);
            b2.setVendors(vList);
            b3.setVendors(vList);

            v1.setBusinesses(bList);
            v2.setBusinesses(bList);

            this.session.save(b1);
            this.session.save(b2);
            this.session.save(b3);

            this.transaction.commit();
        } catch (Exception e) {

            if (this.transaction == null) {

                this.transaction.rollback();
            }
        } finally {

            this.session.close();
        }
    }

    private List<Vendor> getVendorFromBusinessId(Long businessId) {

        List<Vendor> vList = null;
        this.session = SESSION_FACTORY.openSession();
        this.transaction = null;

        try {

            this.transaction = this.session.beginTransaction();
            Business business = (Business) this.session.get(Business.class, businessId);
            vList = business.getVendors();
            this.transaction.commit();
        } catch (Exception e) {

            if (this.transaction == null) {

                this.transaction.rollback();
            }
        } finally {

            this.session.close();
        }

        return vList;
    }

    private void displayVendors(List<Vendor> vList) {

        if (vList != null) {

            System.out.print("Vendor List IDs: ");
            vList.forEach((vendor) -> {
                System.out.print(vendor.getId() + " ");
            });

            System.out.println();
        }
    }
}

希望这能解决您的问题。

我的输出: My Output Image

答案 1 :(得分:0)

在数据库中,我们使用UUID作为主键。但是,构建此应用程序的人员决定不使用Java UUID类型,而是使用String作为UUID。因此,有时应用程序会将小写的UUID发送到数据库,有时它会发送一个大写的UUID。数据库并不关心,因为SQL Server中的UUID不区分大小写,但Java Strings区分大小写,因此Hibernate无法识别具有小写UUID的Business与具有大写UUID的Business。因此,在将它们发送到数据库之前,我必须.toString().toUpperCase()所有ID,以确保它们是相同的。

当然,Java UUID不区分大小写,所以如果构建此软件的人只使用那些而不是String s,那么整个问题就可以避免了。

答案 2 :(得分:0)

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "business_vendor",
        joinColumns = @JoinColumn(name = "business_id"**, referencedColumnName = "enter business Id name"**),
        inverseJoinColumns = @JoinColumn(name = "vendor_id", **referencedColumnName = "enter vendor Id name"** ))
@JSON(include = false)
protected List<Vendor> vendors;

**OR** 

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "business_vendor",
        joinColumns = @JoinColumn(**name = "tablename_idname"**),
        inverseJoinColumns = @JoinColumn(**name = "tablename_idname"**))
@JSON(include = false)
protected List<Vendor> vendors;