1

I have a Spring project using Spring JPA. I have a table for Brands and Products, and I have mapped them through @ManyToMany like so:

BRAND ENTITY:

@Entity
public class Brand{


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = 
"brand_seq_gen")
@SequenceGenerator(name = "brand_seq_gen", sequenceName = "ISEQ$$_73370", allocationSize = 1)
@Column(name = "BRAND_ID")
private Long brandId;

@Column(name = "BRAND_NAME")
private String brandName;

@ManyToMany(fetch = FetchType.LAZY, cascade = {
    CascadeType.ALL
})
@JoinTable(
    name = "BRAND_PRODUCT",
    joinColumns = @JoinColumn(name = "BRAND_ID", referencedColumnName = "BRAND_ID"),
    inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID", referencedColumnName = "PRODUCT_ID")
)
private Set<Product> products = new HashSet<>();    

 //CONSTRUCTORS, SETTERS, AND GETTERS
}

PRODUCT ENTITY:

@Entity
public class Product{


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "prod_seq_gen")
@SequenceGenerator(name = "prod_seq_gen", sequenceName = "ISEQ$$_73373", allocationSize = 1)
@Column(name = "PRODUCT_ID")
private Long productId;

@Column(name = "TYPE_DESCRIPTION")
private String typeDescription;

public Product() {
}

@ManyToMany(mappedBy = "products", fetch = FetchType.LAZY)
private Set<Brand> brands = new HashSet<>();
//Setters, Getters, and Constructors

and for example, I would only want to get the information of Brand only (BRAND_ID and BRAND_NAME) without getting the products, how would I access only the brand's information? Thank you!

--EDIT 1--

I would like to access ALL brands without accessing the products on each brand. Is that possible? Or do I create another class?

--EDIT 2--

Here is a sample query when using BrandRepository.findall()

[ {
 "brandId" : 1,
  "brandName" : "Electrolux",
  "products" : [ {
    "productId" : 4,
    "typeDescription" : "Refrigerator"
  }, {
    "productId" : 3,
    "typeDescription" : "Washing Machine"
  } ]
}, {
  "brandId" : 2,
  "brandName" : "Midea",
  "products" : [ {
    "productId" : 4,
    "typeDescription" : "Refrigerator"
  }, {
    "productId" : 2,
    "typeDescription" : "Air Conditioner"
  }, {
    "productId" : 3,
    "typeDescription" : "Washing Machine"
  } ]
}, {
  "brandId" : 3,
  "brandName" : "Samsung",
  "products" : [ {
    "productId" : 1,
    "typeDescription" : "TV"
  }, {
    "productId" : 4,
    "typeDescription" : "Refrigerator"
  } ]
}, {
  "brandId" : 4,
  "brandName" : "LG",
  "products" : [ {
    "productId" : 1,
    "typeDescription" : "TV"
  } ]
} ]

What I want should only be the columns brandId and brandName without the products resulting from @ManyToMany relationship.

--Edit 4-- I found out through logging that the database is being queried two times to retrieve both tables which is why I think it might be better to just use @Query and a projection.

  • 1
    Please follow [the Java naming convention](https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html) when writing in Java. For method and variable names camelCase is the norm, for classes and interfaces - PascalCase. SNAKE_CASE is used only for static constants and enums. – MartinBG May 21 '20 at 11:59

3 Answers3

2

Use hibernate lazy loading that will fetch only brands, not the child items(products).

Please have a look at this to understand what the lazy loading means.

chirag soni
  • 624
  • 6
  • 18
2

Make sure to have spring.jpa.open-in-view=false in your application.properties file. If you have it set to true you will end up querying database when you call get method on your entity.

marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
  • I think this solved the `FetchType.LAZY` problem, but it induced another problem: the server could no longer initialize a collection of role `products` – Viany Manuel May 21 '20 at 11:55
  • If lazy problem is solved then please use MartinBG solution with projections. https://www.baeldung.com/spring-data-jpa-projections , it should work :) – Aleksander Nuszel May 21 '20 at 12:06
1

The simplest way to fetch just some entity properties is to use projections

Back to your example, you could have a projection interface defined like that:

interface BrandNameAndId {
  Long getId();
  String getBrandName();
}

And a method like this in your Brand's repository:

List<BrandNameAndId > findAllProjectedBy();
MartinBG
  • 1,034
  • 8
  • 13
  • There seems to be a compilation error upon trying to use `Collection allBrandNameAndId()` method, but I am able to put into the `Collection findByBrandName(String brandName)` into my @Repository – Viany Manuel May 22 '20 at 04:14
  • I tried using `@Query("SELECT * FROM BRAND_E", nativeQuery = true)` to method `Collection methodName()`, but the output is null. I also tried it to method `Collection methodName()` but the output now includes `products` field of `Brand` entity. – Viany Manuel May 22 '20 at 08:31
  • @VianyManuel Please use `List findAllProjectedBy();` as repository method name (answer updated) – MartinBG May 22 '20 at 10:20