带有实体管理器的 Micronaut CRUD 操作不适用于带有外键的 table

Micronaut CRUD operation with Entity Manager not working for the table with foreign keys

使用 Micronaut REST API table 上的 CRUD 操作,外键不起作用

我们使用 JPA 和实体管理器创建了一个 micronaut 应用程序。我们 table 调用了 Employee 和 State,因此我们为两者创建了实体 类 并在 employee table.

中引用了 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(RoutingInBoundHandler.java:1240)
        at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:63)
        at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext[=14=](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[=14=](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[=14=](InstrumentedSubscriber.java:80)
        at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
        at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$onNext(ServerRequestTracingPublisher.java:60)
        at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
        at io.micronaut.http.context.ServerRequestTracingPublisher.onNext(ServerRequestTracingPublisher.java:60)
        at io.micronaut.http.context.ServerRequestTracingPublisher.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[=14=](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[=14=](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[=14=](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(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[=14=](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$.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()方法引起的class因为你有:

return state.getStateId();

... 必须抛出 NullPointerException 因为你不测试 state 属性 是否是 null 而 属性 总是null 因为您既没有默认值也没有设置方法。

所以把方法改成这样例如:

public Integer getStateId() {
    return state == null ? null : state.getStateId();
}

同样适用于getStateName()方法,同样的问题。

并将这些方法添加到 Empoyee class 中,以便能够获取和设置 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"
}

isActivecountryNamecountryId 来自 JSON 示例的属性没有意义,因为 Employee 实体中没有它们。