【问题标题】:Micronaut CRUD operation with Entity Manager not working for the table with foreign keys带有实体管理器的 Micronaut CRUD 操作不适用于带有外键的表
【发布时间】:2019-09-11 09:05:14
【问题描述】:

使用 Micronaut REST API CRUD 操作对表进行外键不起作用

我们使用 JPA 和实体管理器创建了一个 micronaut 应用程序。我们有一个名为 Employee 和 State 的表,因此我们为这两个表创建了实体类,并在员工表中引用了 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

我们通过邮递员传递的数据是:

{
        "employeeName": "ATT",
        "address": "address",
        "city": "HYD",
        "isActive": true,
        "stateId": 1,
        "countryName": "India",
        "countryId": 2,
        "stateName": "telangana"
    }

谁能帮忙解决这个问题。

【问题讨论】:

  • 您能否也将提到的错误消息与堆栈跟踪一起添加到问题中?
  • 感谢@cgrim 的回复。请参阅更新后的问题以及您要求的更多详细信息。如果您需要更多详细信息,请告诉我。
  • 我猜问题是你给了 stateId 而不是 State 对象。您可以通过 GET 请求为任何对象提供 JSON 结果吗?
  • 感谢@Eugene Kortov 的及时回复。 crgim 提供了我正在寻找的答案。现在一切正常。

标签: jpa left-join entitymanager micronaut


【解决方案1】:

这个例外:

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 示例中的属性 isActivecountryNamecountryId 没有意义,因为您在 Employee 实体中没有它们。

【讨论】:

  • 感谢@cgrim 的帮助。通过您建议的更改,您可以像魅力一样工作。你真的节省了我的时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多