@EmbeddedId s के साथ दो तालिकाओं के बीच का नक्शा कैसे बनाएं
तो मेरे पास यहां ऐसा चित्र है जो इस तरह दिखता है, जो इस उत्तर में पाया जा सकता है ।
+---------------+ +-------------------+
| PRODUCTS |-----< PRODUCT_VARIANTS |
+---------------+ +-------------------+
| #product_id | | #product_id |
| product_name | | #variant_id |
+---------------+ | sku_id |
| +-------------------+
| |
+--------^--------+ +--------^--------+
| PRODUCT_OPTIONS |-----< VARIANT_VALUES |
+-----------------+ +-----------------+
| #product_id | | #product_id |
| #option_id | | #variant_id |
+--------v--------+ | #option_id |
| | value_id |
+-----------------+ +--------v--------+
| OPTIONS | |
+-----------------+ |
| #option_id | |
| option_name | |
+-----------------+ |
| |
+-------^-------+ |
| OPTION_VALUES |---------------+
+---------------+
| #option_id |
| #value_id |
| value_name |
+---------------+
मैंने अपने स्प्रिंग ऐप में पूरे आरेख को लागू करने में कामयाबी हासिल की, सिवाय तालिका के VARIANT_VALUES
समस्या यह है कि डिज़ाइन से पता चलता है कि तालिकाओं PRODUCT_OPTIONS, OPTION_VALUESऔर PRODUCT_VARIANTSयौगिक Ids (प्राथमिक कुंजी) हैं, जिन्हें मैंने @EmbeddedIdउनमें से तीन पर उपयोग करके कार्यान्वित किया है।
पूर्व की तरह। //PRODUCT_VARIANTS
@Data
@NoArgsConstructor
@Entity
@Table(name = "product_variants")
public class ProductVariant {
@EmbeddedId
private ProductVariantId productVariantId;
@NotNull
private Double price;
@MapsId("productId")
@ManyToOne(fetch = FetchType.LAZY)
private Product product;
//other properties
}
और यह //ProductVariantId
@Data
@Embeddable
public class ProductVariantId implements Serializable {
@EqualsAndHashCode.Include
private Long productVariantId;
@EqualsAndHashCode.Include
private Long productId;
}
अब मैं उन तीन टेबल मैप करने के लिए (की जरूरत है PRODUCT_OPTIONS, OPTION_VALUESऔर PRODUCT_VARIANTSके साथ फिर से)VARIANT_VALUES
इसलिए मैंने इस दृष्टिकोण की कोशिश की //VariantValue
@Data
@NoArgsConstructor
@Entity
@Table(name = "variant_values")
public class VariantValue {
@EmbeddedId
private VariantValueId variantValueId;
@MapsId("productVariantId")
@ManyToOne(fetch = FetchType.LAZY)
private ProductVariant productVariant;
@MapsId("productOptionId")
@ManyToOne(fetch = FetchType.LAZY)
private ProductOption productOption;
@MapsId("optionValueId")
@ManyToOne(fetch = FetchType.LAZY)
private OptionValue optionValue;
}
//VariantValueId
@Embeddable
@Data
public class VariantValueId implements Serializable {
@EqualsAndHashCode.Include
@Embedded
private ProductVariantId productVariantId;
@EqualsAndHashCode.Include
@Embedded
private ProductOptionId productOptionId;
@EqualsAndHashCode.Include
@Embedded
private OptionValueId optionValueId;
}
लेकिन इसने तीनों तालिकाओं में प्रत्येक आईडी के साथ एक तालिका बनाकर समाप्त कर दिया,
जब मैं जोड़ने के एक @Embddedकरने के लिए VariantValueIdयह दो कॉलम उत्पन्न करता है और मैं एक मूल्य को बाहर और अन्य उपयोग करने के लिए किसी भी तरह से नहीं मिल सकता है,
इसलिए उत्पन्न तालिका अब कुछ इस तरह दिखती है //variant_values
product_option_option_option_id [PK]
product_option_ptoduct_product_id [PK]
product_variant_ptoduct_product_id [PK]
product_variant_ptoduct_variant_id [PK]
product_value_option_option_id [PK]
product_value_option_value_id [PK]
इसलिए मैं यह कैसे लागू केवल करने के लिए कर सकते हैं product_id [PK], variant_id [PK], option_id [PK]और value_idडिजाइन से पता चलता है के रूप में?
संपादित करें 1
मैंने क्रिश्चियन बेकोव के दृष्टिकोण की कोशिश की
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "product_variants")
public class ProductVariant extends UserDateAudit {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "productVariantId", column = @Column(name = "variant_id")),
@AttributeOverride(name = "productId", column = @Column(name = "product_id"))
})
private ProductVariantId productVariantId;
@NotNull
private Double price;
//many to many with product entity, option entity and optionValue entity
@MapsId("productId")
@ManyToOne(fetch = FetchType.LAZY)
private Product product;
@OneToMany(mappedBy = "productVariant", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<VariantValue> variantValues;
}
@Data
@Embeddable
public class ProductVariantId implements Serializable {
private Long productVariantId;
private Long productId;
}
@Data
@NoArgsConstructor
@Entity
@Table(name = "variant_values")
public class VariantValue {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "productVariantId", column = @Column(name = "variant_id")),
@AttributeOverride(name = "productId", column = @Column(name = "product_id"))
@AttributeOverride(name = "optionId", column = @Column(name = "option_id")),
@AttributeOverride(name = "valueId", column = @Column(name = "value_id"))
})
private VariantValueId variantValueId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "variant_id", referencedColumnName = "variant_id", insertable = false, updatable = false),
@JoinColumn(name = "product_id", referencedColumnName = "product_id", insertable = false, updatable = false)
})
private ProductVariant productVariant;
//other mappings
मुझे निम्नलिखित त्रुटि मिली
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaAuditingHandler': Cannot resolve reference to bean 'jpaMappingContext' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.hibernate.MappingException: Unable to find column with logical name: product_id in product_variants
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:691) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:197) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1206) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:571) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:925) ~[spring-context-5.3.1.jar:5.3.1]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:588) ~[spring-context-5.3.1.jar:5.3.1]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1309) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1298) ~[spring-boot-2.4.0.jar:2.4.0]
at com.ecommerce.ECommerceApplication.main(ECommerceApplication.java:10) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.0.jar:2.4.0]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.hibernate.MappingException: Unable to find column with logical name: product_id in product_variants
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:609) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330) ~[spring-beans-5.3.1.jar:5.3.1]
... 27 common frames omitted
Caused by: org.hibernate.MappingException: Unable to find column with logical name: product_id in product_variants
at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:854) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:255) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:101) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1823) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1767) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1655) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:286) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1224) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1255) ~[hibernate-core-5.4.23.Final.jar:5.4.23.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.1.jar:5.3.1]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.1.jar:5.3.1]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.1.jar:5.3.1]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]
जवाब
इसके बजाय कुछ इस तरह आज़माएँ:
@Data
@NoArgsConstructor
@Entity
@Table(name = "product_variants")
public class ProductVariant {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "productVariantId", column = @Column(name = "variant_id")),
@AttributeOverride(name = "productId", column = @Column(name = "product_id"))
})
private ProductVariantId productVariantId;
@NotNull
private Double price;
@MapsId("productId")
@ManyToOne(fetch = FetchType.LAZY)
private Product product;
//other properties
}
@Data
@Embeddable
public class ProductVariantId implements Serializable {
@EqualsAndHashCode.Include
private Long productVariantId;
@EqualsAndHashCode.Include
private Long productId;
}
@Data
@NoArgsConstructor
@Entity
@Table(name = "variant_values")
public class VariantValue {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "productVariantId", column = @Column(name = "variant_id")),
@AttributeOverride(name = "productId", column = @Column(name = "product_id")),
@AttributeOverride(name = "optionId", column = @Column(name = "option_id")),
@AttributeOverride(name = "valueId", column = @Column(name = "value_id"))
})
private VariantValueId variantValueId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "variant_id", referencedColumnName = "variant_id", insertable = false, updatable = false),
@JoinColumn(name = "product_id", referencedColumnName = "product_id", insertable = false, updatable = false)
})
private ProductVariant productVariant;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "option_id", referencedColumnName = "option_id", insertable = false, updatable = false),
@JoinColumn(name = "product_id", referencedColumnName = "product_id", insertable = false, updatable = false)
})
private ProductOption productOption;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "option_id", referencedColumnName = "option_id", insertable = false, updatable = false),
@JoinColumn(name = "value_id", referencedColumnName = "value_id", insertable = false, updatable = false)
})
private OptionValue optionValue;
}
@Embeddable
@Data
public class VariantValueId implements Serializable {
@EqualsAndHashCode.Include
private Long productVariantId;
@EqualsAndHashCode.Include
private Long productId;
@EqualsAndHashCode.Include
private Long optionId;
@EqualsAndHashCode.Include
private Long valueId;
}
संपादित करें:
इसे तब आजमाएँ:
@Data
@NoArgsConstructor
@Entity
@Table(name = "product_variants")
public class ProductVariant {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "productVariantId", column = @Column(name = "variant_id")),
@AttributeOverride(name = "productId", column = @Column(name = "product_id"))
})
private ProductVariantId productVariantId;
@NotNull
private Double price;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColum(name = "product_id", insertable = false, updatable = false)
private Product product;
//other properties
}
आप JA को @AttributeOverride एनोटेशन का उपयोग करके अपने कॉलम में एम्बेडेड आईडी के गुणों को मैप करने के लिए बाध्य कर सकते हैं
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "productVariantId", column = @Column(name = "variant_id")),
@AttributeOverride(name = "productId", column = @Column(name = "product_id"))
})
private ProductVariantId productVariantId;
और VariantValueId वर्ग में ProductOptionId और OptionValueId के लिए भी ऐसा ही करें।