Spring Data MongoDB. 生成ID时出错。

23

我进行了一个实验... 将两个Spring Data的存储库合并为一个通用实体: - JPA - MongoDB

首先,我使用以下库版本:

spring-data-jpa:1.7.0.RELEASE spring-data-mongodb:1.6.0.RELEASE

我有一个实体:

@Entity
@Table(name = "ACCOUNTS")
public class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ACCOUNT_ID")
    private Long id;

    @Column(name = "ACCOUNT_NUMBER")
    private String number;

    public Account() {
    }

    public Account(String number) {
        this.number = number;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }
}

JPA Repository 的外观如下:

public interface Repository extends CrudRepository<Account, Long> {
    public Account findByNumber(String number);
}

MongoDB仓库的代码如下:

package ua.home.springdata.investigation.repository.mongo;

public interface Repository extends CrudRepository<Account, Long> {
}

所以......JPA可以工作 :) 没有什么特别的 :) 但是MongoDB的测试没有通过 :( 我收到了一个错误:

org.springframework.dao.InvalidDataAccessApiUsageException: Cannot autogenerate id of type java.lang.Long for entity of type ua.home.springdata.investigation.entity.Account!
    at org.springframework.data.mongodb.core.MongoTemplate.assertUpdateableIdIfNotSet(MongoTemplate.java:1149)
    at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:878)
    at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:833)
    at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:73)
    at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:88)
    at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:442)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:427)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy26.save(Unknown Source)

我认为这是一个非常普遍的情况。为什么Spring Data不能生成Long型实体id?这太奇怪了。


当我添加注释 @GeneratedValue 时,我的IDE会立即抛出错误。我在 'pom.xml' 文件中使用了 jpa 依赖项,但即使如此,它也无法正常工作,因为它搜索的是MySQL数据库,而我正在使用NoSQL(mongoDB)。所以如果您能帮助我解决这个问题,请务必告诉我。谢谢。 - Vibhav Chaddha
@Neil Stockton 当我添加注释 @GeneratedValue 时,我的IDE会立即抛出错误。我已经在我的 'pom.xml' 文件中使用了 jpa 依赖项,但即使如此,它也无法正常工作,因为它搜索的是MySQL数据库,而我正在使用NoSQL(mongoDB)。所以如果您能帮助我解决这个问题,请务必告诉我。提前致谢。 - Vibhav Chaddha
7个回答

38

Mongo的ObjectIds不能映射到Java的Long类型。

我在文档中看到了这个,在7.6.1下:

http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo-template.id-handling

在Java类中声明为String的id属性或字段将被转换为ObjectId并使用Spring的Converter<String, ObjectId>进行存储。有效的转换规则由MongoDB Java驱动程序委托处理。如果无法转换为ObjectId,则该值将作为字符串存储在数据库中。

在Java类中声明为BigInteger的id属性或字段将使用Spring的Converter<BigInteger, ObjectId>转换为ObjectId并存储。

将id更改为String或BigInteger,并删除strategy参数。


1
那我将失去与Spring JPA实现的兼容性 :( - b3lowster
@Robert Moskal 当我添加注释 @GeneratedValue 时,我的IDE会立即抛出错误。我已经在我的 'pom.xml' 文件中使用了 jpa 依赖项,但即使如此,它也无法正常工作,因为它搜索的是MySQL数据库,而我正在使用NoSQL(mongoDB)。所以如果您能帮助我解决这个问题,请务必告诉我。提前致谢。 - Vibhav Chaddha
添加一个新问题并标记我。 - Robert Moskal

9

默认情况下,Mongo集合中的ID是字符串类型。为了维护集合中对象的长ID,您可以选择一个单独的字段,如下所示:

  @Id
  @Field("_id")
  @JsonIgnore
  private String id;

  @Field("my_object_id")
  private Long myObjectId;

8

使用字符串作为@Id是可以的。

确保您的Repository也使用了一个字符串作为继承类型(和@ID一样的类型):

extends MongoRepository<MyEntity, String>

6

我认为问题在于您使用了Entity而不是Document。Mongo dao应该使用Document注释,而存储库应该扩展MongoRepository接口。以下是一个使用您已有内容的示例。首先,您需要将mongo依赖项添加到pom.xml文件中(我假设您正在使用spring boot parent,因此版本号将在那里定义)。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

import org.springframework.data.annotation.Id; 
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "ACCOUNTS")
public class Account {

    @Id
    private String id;

    ....rest of properties
}

import org.springframework.data.mongodb.repository.MongoRepository;
public interface AccountRepository extends MongoRepository<Account, String>  {
    //any extra queries needed
}

2

我也尝试过类似的事情,对于mongo db,我不得不使用import org.springframework.data.annotation.Id;版本的@Id,而对于JPA,我使用import javax.persistence.Id;


1

我的项目使用Spring Data Rest + mongo

  1. 数据类型 我没有使用LongBigInteger类型。它是自定义的对象,比如说CompanyUID.class。这里应该是MongoRepository<DataLoadMerchant, CompanyUID>,就像@Miguel所说的那样。 然后我改变了我的getter和setter。将String转换为CompanyUID或将CompanyUID转换为String

  2. 在Mongo中注册转换器

@Configuration
public class MongoConfig extends AbstractMongoConfiguration {
    @Override
    public CustomConversions customConversions() {
        converters.add(new CompanyUIDoObjectIdConverter());
        converters.add(new ObjectIdToCompanyUIDConverter());
        return new CustomConversions(converters);
    }
}
  1. 列名。 我查看了Mongo文档,似乎不能使用@Id作为entityId的列名。因此,我更改了setter方法。然后在MongoDB中,它将有两个列,一个是_id,另一个是entityId。这两个列保持相同的值。我们只使用entityId作为CRUD的主键,即使它不是真正的主键。

我的代码

public class ClassA implements Serializable {
    @Id
    public CompanyUID id;
    public CompanyUID entityId;

    public String getId() {
        return this.id.toString();
    }

    public void setId(String id) {
        if (id != null && this.entityId != null) {
            if (!id.equals(this.entityId)) {
                throw new Exception();
            }
        }
        this.id = new CompanyUID(id);
        this.entityId = this.id;
    }

    public String getEntityId() {
        return entityId.toString();
    }

    public void setEntityId(String entityId) {
        if (this.id != null && entityId != null) {
            if (!id.equals(entityId)) {
                throw new Exception();
            }
        }

        this.entityId = new CompanyUID(entityId);
        this.id = this.entityId;
    }
}

0

如果您将id作为int或long类型,MongoDb或Jpa将无法用于crud函数。

始终使用字符串数据类型来自动生成变量。


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接