JPA实体在服务层为空

JPA entity is null in service layer

所以我遇到了这个问题,我传递给服务层函数的参数无论如何总是 null。 我得到的错误是由以下原因引起的:java.lang.IllegalArgumentException:给定的 ID 不能为空! 这恰好发生在服务层的 node.get(id) 中,因为该节点为空。

这是我的应用程序的样子:

节点class

@Entity
@Data
public class Node {
    @Id
    @GeneratedValue(strategy = IDENTITY)

    private Long id;

    private int depth;

    private double value;

    @Column(unique=true)
    private String name;

    @ManyToOne //add column definitions as needed
    @JoinColumn(name="parent_id")
    private Node parent;      //each Domain with parent==null is a root domain, all others are subdomains


    @OneToMany(mappedBy = "parent",cascade = {CascadeType.REMOVE,CascadeType.PERSIST}) //add column definitions as needed
    private List<Node> children;

    public Node(final Node parent) {
        if(parent==null) throw new IllegalArgumentException("parent required");

        this.parent = parent;
        this.children = new ArrayList<>();
        if (parent==null) {
            this.depth=0;
        }
        else {
            this.depth = (parent.getDepth() + 1);
        }
        registerInParentsChilds();
    }
    public Node() {
        this.children = new ArrayList<>();
        if (parent==null) {
            this.depth=0;
        }
        else {
            this.depth = (parent.getDepth() + 1);
        }
    }
    /** Register this domain in the child list of its parent. */
    private void registerInParentsChilds() {

        this.parent.children.add(this);
    }

    public List<Node> getChildren() {
        return this.children;
    }
    public void move(final Node newParent)  {
        try {

            this.parent.children.remove(this);
            this.parent = newParent;
            registerInParentsChilds();
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }
    public static Node createRoot() {
        return new Node();
    }


}

节点库:

public interface NodeRepository extends JpaRepository<Node, Long> {
    Optional<Node> findById(Long id);

}

节点服务:

public interface NodeService {
    Node saveNode(Node node);

}

NodeServiceImpl:

@Service @RequiredArgsConstructor @Transactional @Slf4j
public class NodeServiceImpl implements NodeService{

    @Autowired
    private  NodeRepository nodeRepository;

    @Override
    public Node saveNode(Node node) {
        log.info("saving new node {} to DB", node);
        Optional<Node> existing_node = nodeRepository.findById(node.getId());
        if (existing_node.get()!=null) {
            log.info("node already exists");
            return null;

        } else {
            log.info("node saved");
            return nodeRepository.save(node);
        }
    }
}

MainApp

@Bean
    CommandLineRunner run_again(NodeService nodeService) { //this runs after the app is initialized, so no need for
        //manual input
        return args -> {

            Node root;
            root = Node.createRoot();
            nodeService.saveNode(root);
            System.out.println("root created");

            nodeService.saveNode(new Node(root));
            System.out.println("a created");

            Node b = new Node(root);
            nodeService.saveNode(b);

            System.out.println("b created");
            Node c = new Node();
            nodeService.saveNode(c);

            System.out.println("c created");


        };
    }

这是我的错误堆栈(就像我说的,我确切地知道问题出在哪里,但我无法修复它):

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:772) ~[spring-boot-2.6.3.jar:2.6.3]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:753) ~[spring-boot-2.6.3.jar:2.6.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:309) ~[spring-boot-2.6.3.jar:2.6.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) ~[spring-boot-2.6.3.jar:2.6.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) ~[spring-boot-2.6.3.jar:2.6.3]
    at com.example.app.AppApplication.main(AppApplication.java:38) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[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:568) ~[na:na]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.6.3.jar:2.6.3]
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: The given id must not be null!; nested exception is java.lang.IllegalArgumentException: The given id must not be null!
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374) ~[spring-orm-5.3.15.jar:5.3.15]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:235) ~[spring-orm-5.3.15.jar:5.3.15]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551) ~[spring-orm-5.3.15.jar:5.3.15]
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174) ~[spring-data-jpa-2.6.1.jar:2.6.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.15.jar:5.3.15]
    at jdk.proxy4/jdk.proxy4.$Proxy113.findById(Unknown Source) ~[na:na]
    at com.example.app.service.NodeServiceImpl.saveNode(NodeServiceImpl.java:70) ~[classes/:na]
    at com.example.app.service.NodeServiceImpl$$FastClassBySpringCGLIB$$b1b25c7c.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.15.jar:5.3.15]
    at com.example.app.service.NodeServiceImpl$$EnhancerBySpringCGLIB$d60cf81.saveNode(<generated>) ~[classes/:na]
    at com.example.app.AppApplication.lambda$run_again(AppApplication.java:93) ~[classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:769) ~[spring-boot-2.6.3.jar:2.6.3]
    ... 10 common frames omitted
Caused by: java.lang.IllegalArgumentException: The given id must not be null!
    at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.15.jar:5.3.15]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById(SimpleJpaRepository.java:301) ~[spring-data-jpa-2.6.1.jar:2.6.1]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[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:568) ~[na:na]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new[=15=](RepositoryMethodInvoker.java:289) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:529) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:639) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:163) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.15.jar:5.3.15]
    ... 32 common frames omitted

2022-03-08 20:56:00.626  INFO 12604 --- [  restartedMain] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2022-03-08 20:56:00.630  INFO 12604 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2022-03-08 20:56:00.634  INFO 12604 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Process finished with exit code 0

对象节点不为空。如果是,您将在 node.getId() 部分收到 NullPointerException。 什么是 null,是确切的 id。因为您还没有保存节点,因此没有为它生成 id,它仍然是 null。

当您使用@GeneratedValue(strategy = IDENTITY) 配置字段时,该值将在数据库中创建,在保存过程中,因此在保存对象之前该值仍然为空。这意味着你不能通过他们的 id 检查相似对象的存在。您需要检查其他字段。