Spring + Mongodb 与 Null id 问题

Posted

技术标签:

【中文标题】Spring + Mongodb 与 Null id 问题【英文标题】:Spring + Mongodb with a Null id Issue 【发布时间】:2019-02-26 22:45:48 【问题描述】:

我正在使用 Spring + MongoDB 进行学术项目

我有三个文档

用户.java

@Document
public class User implements UserDetails, Serializable 
private static final long SerialVersionUID = 147147L;

@Id
private String id;

private String username;
private String password;
private String firstname;
private String lastname;

private String email;
private String phone;

private boolean enable = true;
private Set<UserRole> userRoles = new HashSet<>();

...


角色.java

@Document
public class Role implements Serializable 
private static final long SerialVersionUID = 456456L;
@Id
private String id;
private String name;
...


UserRole.java

@Document(collection = "user_roles")
public class UserRole implements Serializable 
private static final long SerialVersionUID = 789789L;

@Id
private String id;

@DBRef
private User user;

@DBRef
private Role role;

private String name;

...


还有一个 UserServiceImpl.java

@Service
public class UserServiceImpl implements UserService 
private static final Logger LOG = LoggerFactory.getLogger(UserService.class);

@Autowired
UserRepository userRepository;

@Autowired
RoleRepository roleRepository;

@Autowired
UserRoleRepository userRoleRepository;

@Override
public User createUser(User user, Set<UserRole> userRoles) 
    User localUser = userRepository.findByUsername(user.getUsername());

    if(localUser != null) 
        LOG.info("User with username  already exist. Nothing will be done. ", user.getUsername());
     else 
        for (UserRole ur : userRoles) 
            roleRepository.save(ur.getRole());
            //here is the problem: the userrole instance created cannot generate Id
            userRoleRepository.save(ur);
        

        user.getUserRoles().addAll(userRoles);


        localUser = userRepository.save(user);
    

    return localUser;

还有 DemoApplication.java

@SpringBootApplication
public class DemoApplication implements CommandLineRunner 
@Autowired
UserService userService;

public static void main(String[] args) 
    SpringApplication.run(DemoApplication.class, args);


@Override
public void run(String... args) throws Exception 


User user1 = new User();
user1.setFirstname("John");
user1.setLastname("Adams");
user1.setUsername("j");
    user1.setPassword(SecurityUtility.passwordEncoder().encode("p"));
    user1.setEmail("JAdams@gmail.com");
    Set<UserRole> userRoles = new HashSet<>();
    Role role1 = new Role();
    role1.setName("ROLE_USER");
    UserRole userRole1 = new UserRole();
    userRole1.setRole(role1);
    userRole1.setUser(user1);
    userRoles.add(userRole1);

    userService.createUser(user1, userRoles);


    

和 ExceptionStackTrack

java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:821) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:802) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:341) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1277) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1265) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at com.example.demo.DemoApplication.main(DemoApplication.java:22) [classes/:na]
Caused by: org.springframework.data.mapping.MappingException: Cannot create a reference to an object with a NULL id.
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createDBRef(MappingMongoConverter.java:936) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:554) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeAssociation(MappingMongoConverter.java:517) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeProperties(MappingMongoConverter.java:494) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:481) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:455) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:399) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:78) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.toDocument(MongoTemplate.java:1071) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:1254) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:1202) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:82) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[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:564) ~[na:na]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:641) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:590) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at com.sun.proxy.$Proxy73.save(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[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:564) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at com.sun.proxy.$Proxy73.save(Unknown Source) ~[na:na]
at com.example.demo.Service.Impl.UserServiceImpl.createUser(UserServiceImpl.java:42) ~[classes/:na]
at com.example.demo.DemoApplication.run(DemoApplication.java:46) [classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:818) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
... 5 common frames omitted

这里我不知道为什么角色和用户实例可以自动生成而用户角色不能。控制台向我返回 Id 为 NULL 且不能被引用的异常。

我是新手,希望有人能给我答案。

谢谢。

【问题讨论】:

请包含异常堆栈跟踪 好的,我添加了异常堆栈跟踪 【参考方案1】:

您似乎在调用userRoleRepository.save(ur),以防数据库中不存在具有所提供用户名的User并且在实际存储此User 之前。

我相信你应该重新组织你的代码,首先存储User,然后用这个User集合存储UserRole

换句话说(代码?),在您的UserServiceImpl 中,您可以尝试执行以下操作:

@Override
public User createUser(User user, Set<UserRole> userRoles) 
    User localUser = userRepository.findByUsername(user.getUsername());

    if(localUser != null) 
        LOG.info("User with username  already exist. Nothing will be done. ", user.getUsername());
     else 
        user.getUserRoles().addAll(userRoles);
        localUser = userRepository.save(user);
        for (UserRole ur : userRoles) 
            roleRepository.save(ur.getRole());
            userRoleRepository.save(ur);
        
    

    return localUser;

如您所见,我只对调用进行了重新排序 - 首先存储 User,然后转到 userRoles 以获取此 User

【讨论】:

思路是对的。我检查了用户和用户角色的 id 都是空的,所以它变成了先有鸡还是先有蛋的难题。我将 id 传递给了用户角色,它可以工作,但无法在数据库中创建用户角色表

以上是关于Spring + Mongodb 与 Null id 问题的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB DBRef 列表在 Spring Boot 中返回 null

使用spring boot MongoTemplate删除mongodb记录会抛出错误:“Second is Null”

如何在spring data mongoDB中指定数据库名称

在 MongoDB 中存储 null 与根本不存储密钥

java操作mongodb

Spring -Data MongoDB问题与作为接口的字段