java - 多对多实现错误: id 列不允许 Null
问题描述
我正在尝试实现多对多关系,并且在实现时我一直为 id 列保持自动生成,它给了我错误
“SERVICE_ID”列不允许为 NULL;SQL 语句:
因此,为了避免这种情况,我尝试在保存商家实体的同时手动提供 ID,但仍然出现相同的错误。
示例代码片段:
商家实体
@Entity
@Table(name = "service")
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MerchantEntity {
@Id
@Column(name = "merchant_id")
private Integer merchantId;
@Column(name = "merchant_name")
private String merchantName;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "merchant_service_mapping",
joinColumns = @JoinColumn(name = "merchant_id", referencedColumnName = "merchant_id"),
inverseJoinColumns = @JoinColumn(name = "service_id", referencedColumnName = "service_id"))
private List<ServiceEntity> merchantService;
}
服务实体
@Entity
@Table(name = "service")
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ServiceEntity {
@Id
@Column(name = "service_id")
private Integer serviceId;
@Column(name = "service_name")
private String serviceName;
@ManyToMany(mappedBy = "merchantService")
private List<MerchantEntity> merchants;
}
测试方法
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class EntityMappingApplicationTests {
@Autowired
private MerchantRepository merchantRepository;
@Autowired
private ServiceRepository serviceRepository;
private ServiceEntity serviceEntity1 = null;
private ServiceEntity serviceEntity2 = null;
private ServiceEntity serviceEntity3 = null;
private MerchantEntity merchantEntity1 = null;
private MerchantEntity merchantEntity2 = null;
@BeforeAll
public void setup() {
serviceEntity1 = ServiceEntity.builder()
.serviceId(1)
.serviceName("Plumbing")
.build();
serviceEntity2 = ServiceEntity.builder()
.serviceId(2)
.serviceName("Home Renovation")
.build();
serviceEntity3 = ServiceEntity.builder()
.serviceId(3)
.serviceName("Carpenting")
.build();
List<ServiceEntity> serviceList1 = new ArrayList<>();
serviceList1.add(serviceEntity1);
serviceList1.add(serviceEntity2);
List<ServiceEntity> serviceList2 = new ArrayList<>();
serviceList2.add(serviceEntity1);
serviceList2.add(serviceEntity3);
merchantEntity1 = MerchantEntity.builder()
.merchantId(1)
.merchantName("John's Builder")
.merchantService(serviceList1)
.build();
merchantEntity1 = MerchantEntity.builder()
.merchantId(2)
.merchantName("Jack Repairs")
.merchantService(serviceList2)
.build();
merchantEntity1 = merchantRepository.save(merchantEntity1);
//merchantId1 = merchantEntity1.getMerchantId();
merchantEntity2 = merchantRepository.save(merchantEntity2);
//merchantId2 = merchantEntity2.getMerchantId();
}
@Test
public void testManyToMany() {
MerchantEntity merchant1 = merchantRepository.findById(merchantId1).orElse(null);
assertNotNull(merchant1.getMerchantService());
assertEquals("Plumbing", merchant1.getMerchantService().get(0).getServiceName());
assertEquals("Home Renovation", merchant1.getMerchantService().get(1).getServiceName());
MerchantEntity merchant2 = merchantRepository.findById(merchantId2).orElse(null);
assertNotNull(merchant2.getMerchantService());
assertEquals("Plumbing", merchant2.getMerchantService().get(0).getServiceName());
assertEquals("Carpenting", merchant2.getMerchantService().get(1).getServiceName());
ServiceEntity serviceEntity1 = serviceRepository.findByServiceName("Plumbing");
assertNotNull(serviceEntity1.getMerchants());
assertEquals("John's Builder", serviceEntity1.getMerchants().get(0));
assertEquals("Jack Repairs", serviceEntity1.getMerchants().get(1));
ServiceEntity serviceEntity2 = serviceRepository.findByServiceName("Plumbing");
assertNotNull(serviceEntity2.getMerchants());
assertEquals("John's Builder", serviceEntity2.getMerchants().get(0));
assertEquals("Jack Repairs", serviceEntity2.getMerchants().get(1));
}
}
控制台日志
20:47:05.092 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate]
20:47:05.104 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)]
20:47:05.125 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.shail.entityMapping.EntityMappingApplicationTests] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper]
20:47:05.135 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.shail.entityMapping.EntityMappingApplicationTests], using SpringBootContextLoader
20:47:05.139 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.shail.entityMapping.EntityMappingApplicationTests]: class path resource [com/shail/entityMapping/EntityMappingApplicationTests-context.xml] does not exist
20:47:05.139 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.shail.entityMapping.EntityMappingApplicationTests]: class path resource [com/shail/entityMapping/EntityMappingApplicationTestsContext.groovy] does not exist
20:47:05.140 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [com.shail.entityMapping.EntityMappingApplicationTests]: no resource found for suffixes {-context.xml, Context.groovy}.
20:47:05.140 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [com.shail.entityMapping.EntityMappingApplicationTests]: EntityMappingApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
20:47:05.184 [main] DEBUG org.springframework.test.context.support.ActiveProfilesUtils - Could not find an 'annotation declaring class' for annotation type [org.springframework.test.context.ActiveProfiles] and class [com.shail.entityMapping.EntityMappingApplicationTests]
20:47:05.242 [main] DEBUG org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider - Identified candidate component class: file [C:\Users\ssing\Desktop\entityMapping\target\classes\com\shail\entityMapping\EntityMappingApplication.class]
20:47:05.243 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration com.shail.entityMapping.EntityMappingApplication for test class com.shail.entityMapping.EntityMappingApplicationTests
20:47:05.376 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [com.shail.entityMapping.EntityMappingApplicationTests]: using defaults.
20:47:05.377 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.event.ApplicationEventsTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener]
20:47:05.388 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [javax/servlet/ServletContext]
20:47:05.397 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@626c44e7, org.springframework.test.context.event.ApplicationEventsTestExecutionListener@4dc8caa7, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@1d730606, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@3bcbb589, org.springframework.test.context.support.DirtiesContextTestExecutionListener@3b00856b, org.springframework.test.context.transaction.TransactionalTestExecutionListener@3016fd5e, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@35d08e6c, org.springframework.test.context.event.EventPublishingTestExecutionListener@53d102a2, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@6c45ee6e, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@6b3e12b5, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@5aac4250, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@1338fb5, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@42463763, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener@59f63e24]
20:47:05.404 [main] DEBUG org.springframework.test.context.support.DependencyInjectionTestExecutionListener - Performing dependency injection for test context [[DefaultTestContext@674bd420 testClass = EntityMappingApplicationTests, testInstance = com.shail.entityMapping.EntityMappingApplicationTests@2b0f373b, testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@2ceb80a1 testClass = EntityMappingApplicationTests, locations = '{}', classes = '{class com.shail.entityMapping.EntityMappingApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@66ea810, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@2254127a, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@2d29b4ee, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@13d73f29, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4ee203eb, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@2b6856dd], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]].
20:47:05.436 [main] DEBUG org.springframework.test.context.support.TestPropertySourceUtils - Adding inlined properties to environment: {spring.jmx.enabled=false, org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.4)
2021-09-19 20:47:05.763 INFO 10216 --- [ main] c.s.e.EntityMappingApplicationTests : Starting EntityMappingApplicationTests using Java 16.0.2 on DESKTOP-3GKR7OI with PID 10216 (started by ssing in C:\Users\ssing\Desktop\entityMapping)
2021-09-19 20:47:05.766 INFO 10216 --- [ main] c.s.e.EntityMappingApplicationTests : No active profile set, falling back to default profiles: default
2021-09-19 20:47:06.252 INFO 10216 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2021-09-19 20:47:06.312 INFO 10216 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 51 ms. Found 4 JPA repository interfaces.
2021-09-19 20:47:06.887 INFO 10216 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2021-09-19 20:47:07.085 INFO 10216 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2021-09-19 20:47:07.168 INFO 10216 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2021-09-19 20:47:07.252 INFO 10216 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.4.32.Final
2021-09-19 20:47:07.418 INFO 10216 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2021-09-19 20:47:07.560 INFO 10216 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Hibernate: drop table if exists card CASCADE
Hibernate: drop table if exists merchant_service_mapping CASCADE
Hibernate: drop table if exists passport CASCADE
Hibernate: drop table if exists person CASCADE
Hibernate: drop table if exists person_card_mapping CASCADE
Hibernate: drop table if exists service CASCADE
Hibernate: drop sequence if exists hibernate_sequence
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: create table card (card_id integer not null, card_no varchar(255), cardholder_name varchar(255), expiry_month varchar(255), expiry_year varchar(255), primary key (card_id))
Hibernate: create table merchant_service_mapping (merchant_id integer not null, service_id integer not null)
Hibernate: create table passport (passport_id integer not null, country varchar(255), passport_number varchar(255), passport_type varchar(255), primary key (passport_id))
Hibernate: create table person (person_id integer not null, person_name varchar(255), passport_number integer, primary key (person_id))
Hibernate: create table person_card_mapping (person_id integer not null, card_id integer not null)
Hibernate: create table service (merchant_id integer not null, merchant_name varchar(255), service_id integer not null, service_name varchar(255), primary key (service_id))
Hibernate: alter table person add constraint UK_9tt3moyr2yhcaddgdp1was853 unique (passport_number)
Hibernate: alter table person_card_mapping add constraint UK_nxru3hj8t5ywdcjs3ovd2s691 unique (card_id)
Hibernate: alter table merchant_service_mapping add constraint FKbuhbjw9k0whs5ll5js1b39rpu foreign key (service_id) references service
Hibernate: alter table merchant_service_mapping add constraint FKe0ovuw4u7kolir902qgticayl foreign key (merchant_id) references service
Hibernate: alter table person add constraint FKo5flbgdshfp73k9hdhllj09ec foreign key (passport_number) references passport
Hibernate: alter table person_card_mapping add constraint FKg1knlname54gx6g7h9uu0nm8q foreign key (card_id) references card
Hibernate: alter table person_card_mapping add constraint FK72a27v5da41ycmxlhs43pn2oy foreign key (person_id) references person
2021-09-19 20:47:08.301 INFO 10216 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2021-09-19 20:47:08.310 INFO 10216 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-09-19 20:47:08.947 INFO 10216 --- [ main] c.s.e.EntityMappingApplicationTests : Started EntityMappingApplicationTests in 3.507 seconds (JVM running for 4.558)
Hibernate: select merchanten0_.merchant_id as merchant1_5_1_, merchanten0_.merchant_name as merchant2_5_1_, merchantse1_.merchant_id as merchant1_1_3_, serviceent2_.service_id as service_2_1_3_, serviceent2_.service_id as service_3_5_0_, serviceent2_.service_name as service_4_5_0_ from service merchanten0_ left outer join merchant_service_mapping merchantse1_ on merchanten0_.merchant_id=merchantse1_.merchant_id left outer join service serviceent2_ on merchantse1_.service_id=serviceent2_.service_id where merchanten0_.merchant_id=?
Hibernate: select serviceent0_.service_id as service_3_5_0_, serviceent0_.service_name as service_4_5_0_ from service serviceent0_ where serviceent0_.service_id=?
Hibernate: select serviceent0_.service_id as service_3_5_0_, serviceent0_.service_name as service_4_5_0_ from service serviceent0_ where serviceent0_.service_id=?
Hibernate: insert into service (merchant_name, merchant_id) values (?, ?)
2021-09-19 20:47:09.075 WARN 10216 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23502, SQLState: 23502
2021-09-19 20:47:09.075 ERROR 10216 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : NULL not allowed for column "SERVICE_ID"; SQL statement:
insert into service (merchant_name, merchant_id) values (?, ?) [23502-200]
2021-09-19 20:47:09.104 INFO 10216 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2021-09-19 20:47:09.105 INFO 10216 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
Hibernate: drop table if exists card CASCADE
Hibernate: drop table if exists merchant_service_mapping CASCADE
Hibernate: drop table if exists passport CASCADE
Hibernate: drop table if exists person CASCADE
Hibernate: drop table if exists person_card_mapping CASCADE
Hibernate: drop table if exists service CASCADE
Hibernate: drop sequence if exists hibernate_sequence
2021-09-19 20:47:09.117 INFO 10216 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2021-09-19 20:47:09.120 INFO 10216 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
解决方案
推荐阅读
- .net-core - 如何验证发送到 Azure 函数的参数?
- vb.net - 在 VB.NET 中获取 MP4 属性数据
- c++ - 构建后可执行文件缺少完整库路径
- f# - 如何使用拖放读取 Fable Elmish 中的 Browser.Blob
- c# - 使用 FileStream 的额外字节(或者看起来如此)
- c++ - 如何在为 C++ 设置 Visual Studio Code 时修复一些错误?
- javascript - 在 JSX 中如何从 DataPicker 重定向 Handlesubmit?
- sql - 如何获取 LEFT JOIN 数据的计数
- html - 从 shinyapps.io 将 rmarkdown html 文件保存到本地驱动器
- java - 字符串细分和数据返回问题