使用 Micronaut REST API 对带有外键的表进行 CRUD 操作不起作用
我们使用 JPA 和实体管理器创建了一个 micronaut 应用程序。我们有名为Employee和State的表,因此我们为这两个表创建了实体类,并在employee表中引用了state_id。
通过所有实现,我们能够获取带有状态 ID 和姓名的员工详细信息,但是当我们创建新员工时,它会抛出错误。
员工模型:
package io.usermgmt.models;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "employee_id")
private Integer employeeId;
@Column(name = "employee_name")
private String employeeName;
@Column(name = "address")
private String address;
@Column(name = "city")
private String city;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "state_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private State state;
@Column(name = "zip_code")
private String zipCode;
public Integer getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getAddress(){return address;}
public void setAddress(String address){this.address=address;}
public String getCity(){return city;}
public void setCity(String city){this.city=city;}
public Integer getStateId(){return state.getStateId();}
public String getStateName(){return state.getStateName();}
public String getZipCode(){return zipCode;}
public void setZipCode(String zipCode){this.zipCode=zipCode;}
}
状态模型:
package io.usermgmt.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.Proxy;
import javax.persistence.Column;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "state")
@Proxy(lazy = false)
public class State {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "state_id")
private Integer stateId;
@Column(name = "state_name")
private String stateName;
@OneToMany(mappedBy = "state", fetch = FetchType.LAZY)
@JsonIgnore
private Set<Employee> employees = new HashSet<>();
public Integer getStateId() { return this.stateId; }
public void setStateId(Integer stateId){
this.stateId = stateId;
}
public String getStateName(){ return this.stateName; }
public void setStateName(String stateName){
this.stateName = stateName;
}
}
EmployeeRepositoryImpl
package io.usermgmt.repositories.impl;
import io.usermgmt.models.Client;
import io.usermgmt.repositories.IEmployeeRepository;
import io.micronaut.configuration.hibernate.jpa.scope.CurrentSession;
import io.micronaut.spring.tx.annotation.Transactional;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Optional;
@Singleton
public class EmployeeRepositoryImpl implements IEmployeeRepository {
@PersistenceContext
private EntityManager entityManager;
public EmployeeRepositoryImpl(@CurrentSession EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
@Transactional
public Employee createEmployee(@NotNull Employee employee) {
entityManager.persist(employee);
return employee;
}
@Override
@Transactional
public Employee updateEmployee(@NotNull Employee employee) {
return entityManager.merge(employee);
}
@Override
@Transactional(readOnly = true)
public List<Employee> getAllEmployees() {
String qlString = "SELECT c FROM Employee c";
TypedQuery<Employee> query = entityManager.createQuery(qlString, Employee.class);
return query.getResultList();
}
@Override
@Transactional(readOnly = true)
public Optional<Employee> getEmployeeById(@NotNull Integer id) {
return Optional.ofNullable(entityManager.find(Employee.class, id));
}
}
getAllEmployees() 工作正常,它也获取状态详细信息。但在创建时出现以下错误。
ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: Error encoding object [io.usermgmt.models.Employee@1d91f388] to JSON: (was j
ava.lang.NullPointerException) (through reference chain: io.usermgmt.models.Employee["stateId"])
io.micronaut.http.codec.CodecException: Error encoding object [io.usermgmt.models.Employee@1d91f388] to JSON: (was java.lang.NullPointerException) (through reference chain: io.app
ter.clientmgmt.models.Employee["stateId"])
at io.micronaut.jackson.codec.JsonMediaTypeCodec.encode(JsonMediaTypeCodec.java:176)
at io.micronaut.jackson.codec.JsonMediaTypeCodec.encode(JsonMediaTypeCodec.java:182)
at io.micronaut.http.server.netty.RoutingInBoundHandler.encodeBodyAsByteBuf(RoutingInBoundHandler.java:1359)
at io.micronaut.http.server.netty.RoutingInBoundHandler.encodeBodyWithCodec(RoutingInBoundHandler.java:1305)
at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$subscribeToResponsePublisher$16(RoutingInBoundHandler.java:1240)
at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:63)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.drain(FlowableSwitchMap.java:307)
at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapInnerSubscriber.onSubscribe(FlowableSwitchMap.java:366)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onSubscribe(InstrumentedSubscriber.java:75)
at io.reactivex.internal.operators.flowable.FlowableJust.subscribeActual(FlowableJust.java:34)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.micronaut.reactive.rxjava2.RxInstrumentedCallableFlowable.subscribeActual(RxInstrumentedCallableFlowable.java:65)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.onNext(FlowableSwitchMap.java:129)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.onNext(FlowableSubscribeOn.java:97)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
at io.micronaut.http.context.ServerRequestTracingPublisher$1.lambda$onNext$1(ServerRequestTracingPublisher.java:60)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
at io.micronaut.http.context.ServerRequestTracingPublisher$1.onNext(ServerRequestTracingPublisher.java:60)
at io.micronaut.http.context.ServerRequestTracingPublisher$1.onNext(ServerRequestTracingPublisher.java:52)
at io.reactivex.internal.util.HalfSerializer.onNext(HalfSerializer.java:45)
at io.reactivex.internal.subscribers.StrictSubscriber.onNext(StrictSubscriber.java:97)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FlowableSwitchIfEmpty.java:59)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:68)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
at io.reactivex.internal.operators.flowable.FlowableCreate$NoOverflowBaseAsyncEmitter.onNext(FlowableCreate.java:403)
at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$19(RoutingInBoundHandler.java:1430)
at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:71)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:37)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14868)
at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:288)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run(ExecutorScheduler.java:253)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: io.usermgmt.models.Employee["stateId"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:727)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3905)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsBytes(ObjectMapper.java:3243)
at io.micronaut.jackson.codec.JsonMediaTypeCodec.encode(JsonMediaTypeCodec.java:173)
... 69 common frames omitted
Caused by: java.lang.NullPointerException: null
at io.usermgmt.models.Employee.getStateId(Employee.java:83)
at io.usermgmt.models.$Employee$Introspection$$5.readInternal(Unknown Source)
at io.micronaut.core.beans.AbstractBeanProperty.get(AbstractBeanProperty.java:116)
at io.micronaut.jackson.modules.BeanIntrospectionModule$BeanIntrospectionPropertyWriter.serializeAsField(BeanIntrospectionModule.java:539)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
... 75 common frames omitted
我们通过 poastman 传递的数据是:
{
"employeeName": "ATT",
"address": "address",
"city": "HYD",
"isActive": true,
"stateId": 1,
"countryName": "India",
"countryId": 2,
"stateName": "telangana"
}
任何人都可以帮忙解决这个问题吗?
最佳答案
此异常:
ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: Error encoding object [io.usermgmt.models.Employee@1d91f388] to JSON: (was java.lang.NullPointerException) (through reference chain: io.usermgmt.models.Employee["stateId"])
是由Employee
类中的getStateId()
方法引起的,因为你有:
return state.getStateId();
...它必须抛出 NullPointerException
因为您没有测试 state
属性是否为 null
并且该属性始终为 null
因为你既没有默认值也没有它的设置方法。
因此以这种方式更改方法,例如:
public Integer getStateId() {
return state == null ? null : state.getStateId();
}
这同样适用于 getStateName()
方法,存在同样的问题。
并将这些方法添加到 Empoyee
类中,以便能够获取和设置 state
属性值:
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
正确的 JSON 数据结构为:
{
"employeeName": "ATT",
"address": "address",
"city": "HYD",
"state": {
"stateId": 1,
"stateName": "telangana"},
"zipCode": "zip"
}
JSON 示例中的 属性 isActive
、countryName
和 countryId
没有任何意义,因为您在 Employee 中没有它们
实体。
关于jpa - Micronaut CRUD 操作与实体管理器不适用于具有外键的表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57885691/