Retrieving rows based on a certain criteria regarding a many-to-many mapping in Hibernate

这一生的挚爱 提交于 2020-01-16 08:11:10

问题


I'm just copy & pasting some of the introductory text from one of my questions, since the same table relationship is involved in this question also.


I have three of many tables in Oracle (10g) database as listed below. I'm using Hibernate Tools 3.2.1.GA with Spring version 3.0.2.

  1. Product - parent table
  2. Colour - parent table
  3. ProductColour - join table - references colourId and prodId of Colour and Product tables respectively

Where the table ProductColour is a join table between Product and Colour. As the table names imply, there is a many-to-many relationship between Product and Colour which is mapped by PrductColour. I think, the relationship in the database can easily be imagined and is clear with only this much information. Therefore, I'm not going to explore this relationship at length unnecessarily.

An entity (row) in Product is associated with any number entities in Colour and an entity (row) in Colour can also be associated with any number of entities in Product.


Since, it is a many-to-many relationship, it is mapped in the Product and the Colour entity classes (POJOs) with their respective java.util.Set and no direct POJO class for the product_colour table is available.

The class Product looks like the following.

public class Product  implements java.io.Serializable 
{
    private BigDecimal prodId;
    private Set<Colour> colours = new HashSet<Colour>(0);

    .
    .
    .

    //Other properties with setters and getters. 
}

The class Colour looks like the following.

public class Colour implements java.io.Serializable 
{
    private BigDecimal colourId;
    private Set<Product> products = new HashSet<Product>(0);

    .
    .
    .

    //Other properties with setters and getters. 
}

The actual mapping between entities is available in xxx.hbm.xml files, regarding this question which is unnecessary, I think .


What I want to do is to retrieve only those rows from the Colour table which don't match the colour rows in the ProductColour table for a particular product at a time. In this regard, the native Oracle SQL statement would look something like the following.

SELECT colour_id, colour_name, colour_hex
FROM colour
WHERE colour_id not in (SELECT colour_id FROM product_colour WHERE prod_id=81)
ORDER BY colour_id DESC

Where prod_id can be any valid BigDecimal number in Java which is dynamic.

As noted earlier, the relationship is available as a many-to-many relationship in Hibernate, no POJO class for the database table product_colour is available and therefore, I'm fumbling in writing such an HQL statement in Hibernate. I have tried to write such an HQL statement but no attempts were succeeded.


[The code presented in the rest of the part may completely be unnecessary to review]

I'm therefore following a traditional way. What I'm doing is... I'm first retrieving a single product row from the Product the entity class based on a dynamic value of prodId such as,

List<Product>list=session.createQuery("from Product where prodId=:prodId")
                  .setParameter("prodId", prodId).list();

and then using a loop, I'm getting the entire Colour set - java.util.Set corresponding to the product_colour table in Oracle which is available in the Product entity for this product such as,

Set<Colour>colours=new HashSet<Colour>(0);

for(Product p:list)
{
    if(p!=null)
    {               
        colours=p.getColours();
    }
}

As can be seen, the colours Set is being populated with all of the colour rows available (reference rows) in the product_colour table in Oracle.

After getting all of these rows, I'm getting the entire Colour entity class itself (all the row in it) that corresponds to the colour table in Oracle and then removing those rows which match the rows retrieved from the product_colour Oracle table (available in the colours Set in the preceding snippet) satisfying the condition as mentioned earlier such as,

List<Colour>colourList=session.createQuery("from Colour order by colourId desc").list();
Iterator<Colour>it=colourList.iterator();        

while(it.hasNext())
{
    Colour c=(Colour)it.next();
    for(Colour pc:colours)     //colours is available in the preceding snippet.
    {
        if(c==pc)
        {
            it.remove();
        }
    }
}

This can do what is intended but doing so, may imply some overhead on the system. Additionally, what I want to achieve doesn't seem possible with this approach which is pagination. I can't use the setFirstResult(int) and the setMaxResults(int) methods to accomplish the task of pagination which is the case otherwise like the one shown below regarding the Product entity class,

List<Product> products=session.createQuery("from product order by prodId desc")
                       .setMaxResults(0).setFirstResult(4); 

So the question is again, regarding this relationship, is this possible to write such an HQL statement that can retrieve only those rows from the Colour entity class which don't match the colour rows in the product_colour Oracle table like the native SQL statement shown above?

How can I achieve the concept of pagination otherwise (in case, it is not possible)?


回答1:


Short answer to a veeeeery long question:

select colour from Colour colour 
where colour.id not in (
    select colour2.id from Product product
    inner join product.colours colour2
    where product.id = :productId)


来源:https://stackoverflow.com/questions/13385990/retrieving-rows-based-on-a-certain-criteria-regarding-a-many-to-many-mapping-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!