英文:
@EntityGraph with multiple "attributePaths" or @NamedEntityGraph with multiple "attributeNodes" is not working
问题
I have class Product:
@NamedEntityGraph(
name = "product-excel-entity-graph",
attributeNodes = {
@NamedAttributeNode(value = "productCategoryList", subgraph = "categories"),
@NamedAttributeNode(value = "productImageList", subgraph = "images")
},
subgraphs = {
@NamedSubgraph(name = "categories", attributeNodes = {@NamedAttributeNode("category")}),
@NamedSubgraph(name = "images", attributeNodes = {@NamedAttributeNode("image")})
}
)
public class Product {
@Id
@GeneratedValue(generator = "product_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "product_id_seq", name = "product_seq", allocationSize = 1)
private Long id;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "product")
@JsonIgnore
private List<CategoryProduct> productCategoryList;
@OneToMany(mappedBy = "product")
@JsonIgnore
private List<ProductImage> productImageList;
}
Class CategoryProduct:
@Entity
@Table(name = "category_product")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CategoryProduct {
@Id
@GeneratedValue(generator = "category_product_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "category_product_id_seq", name = "category_product_seq", allocationSize = 1)
private Long id;
@ManyToOne
@JoinColumn(name = "product_id", foreignKey = @ForeignKey(name = "category_product_product_fk"), nullable = false)
private Product product;
@ManyToOne
@JoinColumn(name = "category_id", foreignKey = @ForeignKey(name = "category_product_category_fk"), nullable = false)
private Category category;
}
Class Category:
@Entity
@Table(name = "category")
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = {"categoryProductList"})
public class Category {
@Id
@GeneratedValue(generator = "category_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "category_id_seq", name = "category_seq", allocationSize = 1)
private Long id;
@Column(name = "name", nullable = false)
private String name;
@OneToMany(mappedBy = "category", fetch = FetchType.LAZY)
@JsonIgnore
private List<CategoryProduct> categoryProductList;
}
Class ProductImage:
@Entity
@Table(name = "product_image")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductImage {
@Id
@GeneratedValue(generator = "product_image_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "product_image_id_seq", name = "product_image_seq", allocationSize = 1)
private Long id;
@ManyToOne
@JoinColumn(name = "product_id", foreignKey = @ForeignKey(name = "product_image_product_fk"), nullable = false)
private Product product;
@ManyToOne
@JoinColumn(name = "image_id", foreignKey = @ForeignKey(name = "product_image_image_fk"), nullable = false)
private Image image;
}
Class Image:
@Entity
@Table(name = "image")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Image {
@Id
@GeneratedValue(generator = "image_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "image_id_seq", name = "image_seq", allocationSize = 1)
private Long id;
@Column(name = "img_url")
private String imgUrl;
}
In ProductRepo I have the next method:
@Repository
public interface ProductRepo extends JpaRepository<Product, Long> {
@EntityGraph(value = "product-excel-entity-graph")
List<Product> findAllByIdNotNull();
}
In ProductServiceImpl, the next method:
@Service
public class ProductServiceImpl implements ProductService {
private final ProductRepo productRepo;
private final CategoryRepo categoryRepo;
private final CategoryProductRepo categoryProductRepo;
private final ImageRepo imageRepo;
private final ProductImageRepo productImageRepo;
@Autowired
public ProductServiceImpl(ProductRepo productRepo,
CategoryRepo categoryRepo,
CategoryProductRepo categoryProductRepo,
ImageRepo imageRepo,
ProductImageRepo productImageRepo) {
this.productRepo = productRepo;
this.categoryRepo = categoryRepo;
this.categoryProductRepo = categoryProductRepo;
this.imageRepo = imageRepo;
this.productImageRepo = productImageRepo;
}
@Override
public List<Product> getAllProducts() throws Exception {
try {
List<Product> products = productRepo.findAllByIdNotNull();
if (products.isEmpty()) {
throw new Exception("NO PRODUCT");
}
return products;
} catch (Throwable t) {
throw new Exception(t.getMessage());
}
}
}
The problem is when I am trying to get rows through the productService.getAllProducts(), request returns a 400 status. After I moved repo method call into try-catch, now it just shows a NullPointerException. But it works when I use "attributeNodes" with a single value, the same as code below:
@NamedEntityGraph(
name = "product-excel-entity-graph",
attributeNodes = @NamedAttributeNode(value = "productCategoryList", subgraph = "categories"),
subgraphs = @NamedSubgraph(name = "categories", attributeNodes = {@NamedAttributeNode("category")})
)
or:
@NamedEntityGraph(
name = "product-excel-entity-graph",
attributeNodes = @NamedAttributeNode(value = "productImageList", subgraph = "images"),
subgraphs = @NamedSubgraph(name = "images", attributeNodes = {@NamedAttributeNode("image")})
)
The same problem also with @EntityGraph. It does not work with multiple values as in code below:
@EntityGraph(attributePaths = {"productCategoryList", "productImageList"})
List<Product> findAll();
But works with a single value:
@EntityGraph(attributePaths = {"productCategoryList"})
List<Product> findAll();
and
@EntityGraph(attributePaths = {"productImageList"})
List<Product> findAll();
How to fix it?
英文:
I have class Product:
@NamedEntityGraph(
name = "product-excel-entity-graph",
attributeNodes = {
@NamedAttributeNode(value = "productCategoryList", subgraph = "categories"),
@NamedAttributeNode(value = "productImageList", subgraph = "images")
}
,
subgraphs = {
@NamedSubgraph(name = "categories", attributeNodes = {@NamedAttributeNode("category")}),
@NamedSubgraph(name = "images", attributeNodes = {@NamedAttributeNode("image")})
}
)
public class Product {
@Id
@GeneratedValue(generator = "product_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "product_id_seq", name = "product_seq", allocationSize = 1)
private Long id;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "product")
@JsonIgnore
private List<CategoryProduct> productCategoryList;
@OneToMany(mappedBy = "product")
@JsonIgnore
private List<ProductImage> productImageList;
}
Class CategoryProduct:
@Entity
@Table(name = "category_product")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CategoryProduct {
@Id
@GeneratedValue(generator = "category_product_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "category_product_id_seq", name = "category_product_seq", allocationSize = 1)
private Long id;
@ManyToOne
@JoinColumn(name = "product_id", foreignKey = @ForeignKey(name = "category_product_product_fk"), nullable = false)
private Product product;
@ManyToOne
@JoinColumn(name = "category_id", foreignKey = @ForeignKey(name = "category_product_category_fk"), nullable = false)
private Category category;
}
Class Category:
@Entity
@Table(name = "category")
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = {"categoryProductList"})
public class Category {
@Id
@GeneratedValue(generator = "category_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "category_id_seq", name = "category_seq", allocationSize = 1)
private Long id;
@Column(name = "name", nullable = false)
private String name;
@OneToMany(mappedBy = "category", fetch = FetchType.LAZY)
@JsonIgnore
private List<CategoryProduct> categoryProductList;
}
Class ProductImage:
@Entity
@Table(name = "product_image")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductImage {
@Id
@GeneratedValue(generator = "product_image_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "product_image_id_seq", name = "product_image_seq", allocationSize = 1)
private Long id;
@ManyToOne
@JoinColumn(name = "product_id", foreignKey = @ForeignKey(name = "product_image_product_fk"), nullable = false)
private Product product;
@ManyToOne
@JoinColumn(name = "image_id", foreignKey = @ForeignKey(name = "product_image_image_fk"), nullable = false)
private Image image;
}
Class Image:
@Entity
@Table(name = "image")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Image {
@Id
@GeneratedValue(generator = "image_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "image_id_seq", name = "image_seq", allocationSize = 1)
private Long id;
@Column(name = "img_url")
private String imgUrl;
}
In ProductRepo I have next method:
@Repository
public interface ProductRepo extends JpaRepository<Product, Long> {
@EntityGraph(value = "product-excel-entity-graph")
List<Product> findAllByIdNotNull();
}
In ProductServiceImpl next method:
@Service
public class ProductServiceImpl implements ProductService {
private final ProductRepo productRepo;
private final CategoryRepo categoryRepo;
private final CategoryProductRepo categoryProductRepo;
private final ImageRepo imageRepo;
private final ProductImageRepo productImageRepo;
@Autowired
public ProductServiceImpl(ProductRepo productRepo,
CategoryRepo categoryRepo,
CategoryProductRepo categoryProductRepo,
ImageRepo imageRepo,
ProductImageRepo productImageRepo) {
this.productRepo = productRepo;
this.categoryRepo = categoryRepo;
this.categoryProductRepo = categoryProductRepo;
this.imageRepo = imageRepo;
this.productImageRepo = productImageRepo;
}
@Override
public List<Product> getAllProducts() throws Exception {
try{
List<Product> products = productRepo.findAllByIdNotNull();
if (products.isEmpty()) {
throw new Exception("NO PRODUCT");
}
return products;
} catch (Throwable t){
throw new Exception(t.getMessage());
}
}
}
The problem is when I am trying to get rows through the productService.getAllProducts(), request returns 400 status. After I moved repo method call into try-catch, now it just shows NullPointerException. But it works when I use "attributeNodes" with single value same as code below:
@NamedEntityGraph(
name = "product-excel-entity-graph",
attributeNodes = @NamedAttributeNode(value = "productCategoryList", subgraph = "categories"),
subgraphs = @NamedSubgraph(name = "categories", attributeNodes = {@NamedAttributeNode("category")})
)
or:
@NamedEntityGraph(
name = "product-excel-entity-graph",
attributeNodes = @NamedAttributeNode(value = "productImageList", subgraph = "images"),
subgraphs = @NamedSubgraph(name = "images", attributeNodes = {@NamedAttributeNode("image")})
)
The same problem also with @EntityGraph. It does not work with multiple values as in code below:
@EntityGraph(attributePaths = {"productCategoryList", "productImageList"})
List<Product> findAll();
But works with single value:
@EntityGraph(attributePaths = {"productCategoryList"})
List<Product> findAll();
and
@EntityGraph(attributePaths = {"productImageList"})
List<Product> findAll();
How to fix it?
答案1
得分: 1
The solution is fairly simple use JPA 2.1 where you need add entity graph at JPA repository only.
@Repository
public interface ProductRepo extends JpaRepository<Product, Long> {
@EntityGraph(attributePaths = {"productCategoryList" , "productImageList" })
List<Product> findAllByIdNotNull();
}
This will create a join between the bi-directional mapping of Product with CategoryProduct and ProductImage.
For nested level, you can do this.
@EntityGraph(attributePaths = {"userCategories", "userCategories.userSubCategories"})
List<BnbUser> findAll();
You need to override the equals
method in each of these entity classes with an ID; otherwise, this will not work. You can get rid of complex multilevel NamedEntityGraph at each entity class, which is not needed.
英文:
The solution is fairly simple use JPA 2.1 where you need add entiry grapgh at JPA repository only
@Repository
public interface ProductRepo extends JpaRepository<Product, Long> {
@EntityGraph(attributePaths = {"productCategoryList" ,
"productImageList" })
List<Product> findAllByIdNotNull();
}
This will create Join between the bi-directional mapping of Product with CategoryProduct and ProductImage
For nested level you can do this
@EntityGraph(attributePaths = {""userCategories" ,"userCategories.userSubCategories"})
List<BnbUser> findAll();
> Blockquote you need to override equals method in each of these entity classes with ID else this will not work. You can get rid of complex multilevel NamedEntityGraph at each entity class which is not needed
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论