java - 如何在Java Spring中从Hibernate双向OneToMany ManyToOne中检索数据

Posted

技术标签:

【中文标题】java - 如何在Java Spring中从Hibernate双向OneToMany ManyToOne中检索数据【英文标题】:How to retrieve data from Hibernate bidirectional OneToMany ManyToOne in Java Spring 【发布时间】:2017-01-10 21:54:46 【问题描述】:

这听起来确实是一个简单的问题,但我真的找不到任何有用的东西。

我的问题是如何从双向 ManytoOne 关联中使用条件(或其他)获取数据库条目?

假设我们有 2 个类。

@Entity
@Table(name="tCategory")
public class Category 

    @Id
    @Column(table="tCategory")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int category_id;

    @OneToMany(cascade = CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, mappedBy="category")
    private Set<SubCategory> subcategory;

    ..............
    public Set<SubCategory> getSubcategory() 
        return subcategory;
    
    public void setSubcategory(Set<SubCategory> subcategory) 
        this.subcategory = subcategory;
    

    public int getCategory_id() 
        return category_id;
    
    public void setCategory_id(int category_id) 
        this.category_id = category_id;
    
    ..............
    @Override
    public String toString() 
        return "Category [category_id=" + category_id + ", subcategory=" + subcategory + "]";
    



@Entity
@Table(name="tSubCategory")
public class SubCategory 

    @Id
    @Column(table="tSubCategory")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int subcategory_id;

    @ManyToOne(cascade = CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH)
    @JoinColumn(name="category_id")
    private Category category;

    public Category getCategory() 
        return category;
    

    ........

    public void setCategory(Category category) 
        this.category = category;
    

    public int getSubcategory_id() 
        return subcategory_id;
    
    public void setSubcategory_id(int subcategory_id) 
        this.subcategory_id = subcategory_id;
    

    ........
    @Override
    public String toString() 
        return "Category [category_id=" + category_id + ", subcategory=" + subcategory + "]";
    

如我们所见,我们有 1 个类别的许多子类别。

问题是如何获得 category_id = 1 的所有子类别?

schema description

我想要做的是:

public List<SubCategory> getSubCategoriesById(int category_id) 
        Session session = null;
        Transaction tx = null;
        try
            session = this.sessionFactory.openSession();
            tx = session.beginTransaction();
            List<SubCategory> subcategories;
            Criterion cr = Restrictions.eq("category.category_id",category_id);
            subcategories = session.createCriteria(SubCategory.class).add(cr).list();
            tx.commit();
            return subcategories;
         catch (Exception e) 
            e.printStackTrace();
            tx.rollback();
         finally 
            session.close();
        
        return null;
    

然后在我的控制器上

@RequestMapping("/loadSubCategories")
    public @ResponseBody List<SubCategory> loadSubCategories(@RequestParam int id) 

        List<SubCategory> subcategories = hierarchyDAO.getSubCategoriesById(id);
        System.out.println(subcategories.get(0));
        return subcategories;
    

我收到以下错误

2017-01-10 23:38:33 DEBUG DispatcherServlet:984 - Could not complete request
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: contacts.resources.Category.subcategory, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)

我确信我们正在检索看到 hibernate 正在记录的查询的类别列值。

有什么想法吗?

我在这里添加了一些信息,因为我认为我们从数据库中获得了正确的信息,但是延迟加载有问题。

我以这种方式更改了 getSubCategoriesById:

    @Override
        public List<SubCategory> getSubCategoriesById(int category_id) 
            Session session = this.sessionFactory.openSession();
            Transaction tx = session.beginTransaction();

            Criterion cr = Restrictions.eq("category.category_id",category_id);
            List<SubCategory> subcategories = session.createCriteria(SubCategory.class).add(cr).list();
            tx.commit();
            session.close();

            return subcategories;
        

and I am tried to log the results on controller.

@RequestMapping(value="/loadSubCategories", produces = "application/json")
    public @ResponseBody List<SubCategory> loadSubCategories(@RequestParam int id) 
        System.out.println("->apo get" + id);

        List<SubCategory> subcategories = hierarchyDAO.getSubCategoriesById(id);
        System.out.println("size: " + subcategories.size());

        int i = 0;
        while (i < subcategories.size()) 
            System.out.println("category name " + subcategories.get(i).getCategory().getName());
            System.out.println("subcategory name " + subcategories.get(i).getName());
            System.out.println("subcategory details " + subcategories.get(i).getDetails());
            i++;
        

        return subcategories;
    

这里是日志:

2017-01-11 19:11:16 DEBUG LogicalConnectionImpl:264 - Released JDBC connection
size: 3
category name Clothing
subcategory name Fixes
subcategory details clothes fixes
category name Clothing
subcategory name Other
subcategory details Not
category name Clothing
subcategory name Other
subcategory details Not listed
2017-01-11 19:11:16 DEBUG ExceptionHandlerExceptionResolver:134 - Resolving exception from handler [public java.util.List<contacts.resources.SubCategory> contacts.controllers.TransactionController.loadSubCategories(int)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: contacts.resources.Category.subcategory, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->contacts.resources.SubCategory["category"]->contacts.resources.Category["subcategory"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: contacts.resources.Category.subcategory, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->contacts.resources.SubCategory["category"]->contacts.resources.Category["subcategory"])
2017-01-11 19:11:16 DEBUG ResponseStatusExceptionResolver:134 - Resolving exception from handler [public java.util.List<contacts.resources.SubCategory> contacts.controllers.TransactionController.loadSubCategories(int)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: contacts.resources.Category.subcategory, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->contacts.resources.SubCategory["category"]->contacts.resources.Category["subcategory"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: contacts.resources.Category.subcategory, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->contacts.resources.SubCategory["category"]->contacts.resources.Category["subcategory"])
2017-01-11 19:11:16 DEBUG DefaultHandlerExceptionResolver:134 - Resolving exception from handler [public java.util.List<contacts.resources.SubCategory> contacts.controllers.TransactionController.loadSubCategories(int)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: contacts.resources.Category.subcategory, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->contacts.resources.SubCategory["category"]->contacts.resources.Category["subcategory"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: contacts.resources.Category.subcategory, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->contacts.resources.SubCategory["category"]->contacts.resources.Category["subcategory"])
2017-01-11 19:11:16 DEBUG HstsHeaderWriter:130 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@76e1cd21

这里的奇怪部分是我能够记录信息,但 JSON 映射中缺少某些内容。它似乎试图这样做:

subcategories.get(0).getCategory().getSubcategory().get(0).getName();

精确文件:

public class HierarchyDAOImpl implements HierarchyDAO 

private SessionFactory sessionFactory;

public HierarchyDAOImpl(SessionFactory sessionFactory) 
    this.sessionFactory = sessionFactory;


@Override
public List<Category> getAllCategories() 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    List<Category> categories;
    categories = session.createCriteria(Category.class).list();
    tx.commit();
    session.close();
    return categories;


@Override
public List<SubCategory> getAllSubCategories() 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    List<SubCategory> subcategories;
    subcategories = session.createCriteria(SubCategory.class).list();
    tx.commit();
    session.close();
    return subcategories;


@Override
public Category getCategory(int id) 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    Category category = (Category) session.get(Category.class, id);
    tx.commit();
    session.close();
    return category;


@Override
public SubCategory getSubCategory(int id) 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    SubCategory subcategory = (SubCategory) session.get(SubCategory.class, id);
    tx.commit();
    session.close();
    return subcategory;


@Override
public int createCategory(Category category) 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    session.saveOrUpdate(category);
    tx.commit();
    session.close();
    return category.getCategory_id();


@Override
public int createSubCategory(SubCategory subcategory) 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    session.saveOrUpdate(subcategory);
    tx.commit();
    session.close();
    return subcategory.getSubcategory_id();


@Override
public int deleteCategory(Category category) 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    session.delete(category);
    tx.commit();
    session.close();
    return 1;


@Override
public int deleteSubCategory(SubCategory subcategory) 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    session.delete(subcategory);
    tx.commit();
    session.close();
    return 1;


@Override
public List<SubCategory> getSubCategoriesById(int category_id) 
    Session session = this.sessionFactory.openSession();
    Transaction tx = session.beginTransaction();


    Query query = session.createQuery("from tCategory c inner join fetch c.subcategory where c.category_id = :id");

    List<SubCategory> subcategories = query.setParameter("id", category_id).list();
    tx.commit();
    session.close();

    return subcategories;

@Entity

@Table(name="tCategory") 公共类类别

@Id
@Column(table="tCategory")
@GeneratedValue(strategy = GenerationType.AUTO)
private int category_id;
@Column(table="tCategory")
private String name;
@Column(table="tCategory")
private int sort;
@Column(table="tCategory")
private String color;
@Column(table="tCategory")
private int icon_id;
@Column(table="tCategory")
private String details;
@OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, mappedBy="category")
private List<SubCategory> subcategory;

public int getCategory_id() 
    return category_id;

public void setCategory_id(int category_id) 
    this.category_id = category_id;

public String getName() 
    return name;

public void setName(String name) 
    this.name = name;

public int getSort() 
    return sort;

public void setSort(int sort) 
    this.sort = sort;

public String getColor() 
    return color;

public void setColor(String color) 
    this.color = color;

public int getIcon_id() 
    return icon_id;

public void setIcon_id(int icon_id) 
    this.icon_id = icon_id;

public String getDetails() 
    return details;

public void setDetails(String details) 
    this.details = details;


public List<SubCategory> getSubcategory() 
    return subcategory;

public void setSubcategory(List<SubCategory> subcategory) 
    this.subcategory = subcategory;

@Override
public String toString() 
    return "Category [category_id=" + category_id + ", name=" + name + ", sort=" + sort + ", color=" + color
            + ", icon_id=" + icon_id + ", details=" + details + ", subcategory=" + subcategory + "]";

@Entity

@Table(name="tSubCategory") 公共类子类别

@Id
@Column(table="tSubCategory")
@GeneratedValue(strategy = GenerationType.AUTO)
private int subcategory_id;
@Column(table="tSubCategory")
private String name;
@Column(table="tSubCategory")
private int sort;
@Column(table="tSubCategory")
private String color;
@Column(table="tSubCategory")
private int icon_id;
@Column(table="tSubCategory")
private String details;
@ManyToOne(cascade = CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH)
@JoinColumn(name="category_id")
private Category category;

public int getSubcategory_id() 
    return subcategory_id;

public void setSubcategory_id(int subcategory_id) 
    this.subcategory_id = subcategory_id;

public String getName() 
    return name;

public void setName(String name) 
    this.name = name;

public int getSort() 
    return sort;

public void setSort(int sort) 
    this.sort = sort;

public String getColor() 
    return color;

public void setColor(String color) 
    this.color = color;

public int getIcon_id() 
    return icon_id;

public void setIcon_id(int icon_id) 
    this.icon_id = icon_id;

public String getDetails() 
    return details;

public void setDetails(String details) 
    this.details = details;

public Category getCategory() 
    return category;

public void setCategory(Category category) 
    this.category = category;

@Override
public String toString() 
    return "SubCategory [subcategory_id=" + subcategory_id + ", name=" + name + ", sort=" + sort + ", color="
            + color + ", icon_id=" + icon_id + ", details=" + details + ", category=" + category + "]";

【问题讨论】:

您的会话在您使用集合之前已关闭。 finally session.close(); 我不认为它与错误有关,因为从控制器我能够获得 SubCategory 值,例如subcategories.get(0).getSubcategory_id();当我尝试从子类别访问类别对象时遇到问题,例如subcategories.get(0).getCategory(); 如果不是,则说明休眠会话使用的对象的生命周期。 一对多和多对一的默认获取类型是 LAZY 。尝试定义 FetchType.EAGER 并尝试一下 【参考方案1】:

您可以使用 Hibernate 查询语言使用以下查询轻松执行此操作。

Query query = session.createQuery("from Category c inner join fetch c.subCategory where c.category_id := id");

query.setParamter("id", yourId);

这将获取一个类别以及所有关联的子类别

【讨论】:

我想知道除了使用 HQL 是否还有其他方法可以做到这一点。我会试试你的解决方案,我会告诉你的。 我收到这个错误:org.hibernate.hql.internal.ast.QuerySyntaxException: tCategory is not mapped [from tCategory c inner join fetch c.tSubCategory where c.category_id = :id]跨度> 正如异常提到的,这是一个语法问题。我认为您错过了在查询中键入子类别属性。不应该是inner join fetch c.subcategory 而不是c.subCategory。 还有其他方法可以做到这一点,例如指定 fetch 类型急切,但你失去了延迟加载的好处。 你在写。现在我得到 org.hibernate.hql.internal.ast.QuerySyntaxException: tCategory is not mapped [from tCategory c inner join fetch c.subcategory where c.category_id = :id]

以上是关于java - 如何在Java Spring中从Hibernate双向OneToMany ManyToOne中检索数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 Gradle 在 Spring Boot 项目中从 Kotlin 测试中引用 Java 代码时未解决的引用

尝试在 Java Spring Boot 中从 H2 数据库中获取相关实体

如何在 JSP 页面中从 Java 类中设置 hashmap 的值以便在控制器中进一步使用

在 Spring MVC 中从 Controller 显示视图(所有员工的列表)

如何在 Java 中从 ArrayList 中切出 ArrayList?

如何在 Android Studios 中从 java 类到 kotlin 类