I’m encountering an issue with a @ManyToMany
mapping in my Spring Boot application using Hibernate. The problem arises when Hibernate tries to execute a query involving the join table for a Set<Asset>
in the Product
entity.
Error Message:
JDBC exception executing SQL [select i1_0.variant_id,i1_1.asset_id,i1_1.date_created,i1_1.file_name,i1_1.file_path,i1_1.file_type,i1_1.last_updated,i1_1.size_in_bytes,i1_1.url from product_images i1_0 join assets i1_1 on i1_1.asset_id=i1_0.images_asset_id where i1_0.variant_id=?] [Unknown column 'i1_0.images_asset_id' in 'on clause']
It seems that Hibernate is looking for a column named images_asset_id
, which means it is likely generating the SQL query based on a default naming convention rather than the specified @JoinTable
and @JoinColumn
annotations.
Database Schema:
assets table:
CREATE TABLE IF NOT EXISTS assets
(
asset_id BIGINT AUTO_INCREMENT PRIMARY KEY,
file_name VARCHAR(255),
file_path VARCHAR(255),
file_type VARCHAR(50),
url VARCHAR(400),
size_in_bytes BIGINT NULL DEFAULT 0,
date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
products table:
CREATE TABLE IF NOT EXISTS products
(
product_id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description LONGTEXT,
handle VARCHAR(255),
price DECIMAL(10, 2) NOT NULL,
min_price DECIMAL(10, 2),
max_price DECIMAL(10, 2),
variant_count INT DEFAULT 0,
inventory_tracking ENUM ('PRODUCT', 'VARIANT') DEFAULT 'PRODUCT',
product_type VARCHAR(255),
quantity INT DEFAULT 0,
currency_id BIGINT,
date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (currency_id) REFERENCES currencies (currency_id)
);
product_images table:
CREATE TABLE IF NOT EXISTS product_images
(
product_image_id BIGINT AUTO_INCREMENT PRIMARY KEY,
asset_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
variant_id BIGINT,
date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT uc_image UNIQUE (product_id, variant_id, asset_id),
FOREIGN KEY (product_id) REFERENCES products (product_id) ON DELETE CASCADE,
FOREIGN KEY (variant_id) REFERENCES product_variants (variant_id) ON DELETE SET NULL,
FOREIGN KEY (asset_id) REFERENCES assets (asset_id) ON DELETE CASCADE
);
Entity Classes:
Product Entity:
@Entity
@Table(name = "products")
@EntityListeners(AuditingEntityListener.class)
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "product_id", nullable = false, updatable = false)
private Long productId;
// other fields
@ManyToMany
@JoinTable(
name = "product_images",
joinColumns = @JoinColumn(name = "product_id"),
inverseJoinColumns = @JoinColumn(name = "asset_id")
)
private Set<Asset> images;
@CreatedDate
@Column(nullable = false, updatable = false)
private OffsetDateTime dateCreated;
@LastModifiedDate
@Column(nullable = false)
private OffsetDateTime lastUpdated;
// getters and setters
}
Asset Entity:
@Entity
@Table(name = "assets")
@EntityListeners(AuditingEntityListener.class)
public class Asset {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "asset_id", nullable = false, updatable = false)
private Long assetId;
@Column(name = "file_name")
private String fileName;
@Column(name = "file_path")
private String filePath;
@Column(name = "size_in_bytes")
private Long sizeInBytes;
@Column(name = "file_type", length = 50)
private String fileType;
@Column
private String url;
@CreatedDate
@Column(nullable = false, updatable = false)
private OffsetDateTime dateCreated;
@LastModifiedDate
@Column(nullable = false)
private OffsetDateTime lastUpdated;
@ManyToMany(mappedBy = "images")
private Set<Product> products;
// getters and setters
}
Application Configuration:
Main Application Class:
@SpringBootApplication(scanBasePackages = {"com.syeta.common","com.syeta.admin"})
@EnableJpaRepositories(basePackages = "com.syeta.common.repos")
@EntityScan(basePackages = "com.syeta.common.domain")
public class SyetaAdminApplication {
public static void main(String[] args) {
SpringApplication.run(SyetaAdminApplication.class, args);
}
}
Problem Description:
Despite correctly defining the @ManyToMany
relationship between Product
and Asset
entities using the product_images
join table, Hibernate is generating an SQL query that looks for a non-existent column images_asset_id
in the product_images
table.
What might be causing Hibernate to generate an incorrect column name in the SQL query? How can I resolve this issue to correctly map the Set<Asset>
in the Product
entity?
Any insights or suggestions would be greatly appreciated.
What I Tried
- Verified the
product_images
table has correct columnsproduct_id
andasset_id
. - Confirmed
Product
andAsset
entities are correctly annotated. - Checked
@EnableJpaRepositories
,@EntityScan
, and@ComponentScan
in the main application class. - Performed
mvn clean install
to rebuild the project. - Enabled SQL logging to inspect generated queries.
Expected vs. Actual Result
I expected Hibernate to map the @ManyToMany
relationship correctly and generate SQL queries with product_id
and asset_id
. Instead, it generated a query with images_asset_id
, causing the error.
Question
What might be causing Hibernate to generate an incorrect column name in the SQL query? How can I resolve this issue?