MongoDB中_class字段的作用

我们知道,如果你用Java的Sping Data 框架映射Pojo为MongoDB数据时,数据库中会自动给你添加一个_class字段,那这个字段是干嘛用的呢?我们可以不可以不要这个字段呢?

直接上结论:答案其实很简答,这个字段就是用来映射Pojo的,更具体的说,是为了方便处理Pojo中存在继承的情况,增加系统的扩展性的,接下来上例子:

_class字段帮助映射子类

为了方便演示,这里用Spring Data 给我们提供的mongoTemplate来操作。有关mongoDB和Spring Data的环境我就不贴了,直接上测试代码:

拥有继承关系的实体类

@Document是把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。

父类Person

@Document(collection = "test")
public class Person {

  protected String name;
  protected int age;

//set/get方法
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
}

子类 Student

@Document(collection = "test")
public class Student extends Person {

  String a;
  String b;

  @Override
  public String toString() {
    return "Student{" +
        "name='" + name + '\'' +
        ", age=" + age +
        ", a='" + a + '\'' +
        ", b='" + b + '\'' +
        '}';
  }

  public String getA() {
    return this.a;
  }

  public void setA(String a) {
    this.a = a;
  }

  public String getB() {
    return this.b;
  }

  public void setB(String b) {
    this.b = b;
  }
}

Dao层

Dao接口

public interface PersonDao {
  void addPerson(Person person);
  Person findPersonByName(String name);
}

Dao实现

@Repository
public class PersonDapImpl implements PersonDao {

  @Autowired
  MongoTemplate mongoTemplate;
  
  @Override
  public void addPerson(Person person) {
    mongoTemplate.save(person);
  }

  @Override
  public Person findPersonByName(String name) {
    Query query = new Query(Criteria.where("name").is(name));
    Person person = mongoTemplate.findOne(query, Person.class);
    return person;
  }
}

测试方法

public class PersonDapImplTest extends BaseTest {

  @Autowired
  PersonDao personDao;

  @Test
  public void addPerson() {
    Person person = new Person();
    person.setName("张");
    person.setAge(10);
    personDao.addPerson(person);
  }

  @Test
  public void addStudent() {
    Student student = new Student();
    student.setName("小张");
    student.setAge(12);
    student.setA("a");
    student.setB("b");
    personDao.addPerson(student);
  }

  @Test
  public void findPerson() {
    System.out.println("==============开始查找==============");

    Person person = personDao.findPersonByName("小张");

    System.out.println();
    System.out.println();
    System.out.println();

    if (person != null) {
      System.out.println(person.toString());
    }else {
      System.out.println("null");
    }
  }
}

测试结论

测试中,小张是张的子类,mongoDB中已经插入了2条数据:

查询小张,得到的类是Student类吗?

可以看到,最终展示的是Student的详细信息,说明_class能帮助我们反序列化出子类。

那如果去掉了_class列,会是什么样呢?

去掉_class

去掉_class的方法需要配置一下

需要配置MappingConverter:更详细的去掉_class的方法可以参考其他博文。

  @Bean
  public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory,
      MongoMappingContext context, BeanFactory beanFactory, CustomConversions conversions) {
    DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
    MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
    // remove _class field
//    mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
    mappingConverter.setCustomConversions(conversions);
    return mappingConverter;
  }

去掉_class后:

再次查询"小张"

可以看到,mongoDB无法帮助我们来映射子类了。返回的数据被反序列化成了Person类。

posted @ 2018-11-16 15:21  上帝爱吃苹果-Soochow  阅读(9852)  评论(0编辑  收藏  举报