1. 程式人生 > >Spring Data Jpa 配合MongoDB實現持久層物件屬性動態增加

Spring Data Jpa 配合MongoDB實現持久層物件屬性動態增加

MongoDB作為NOSQL資料庫,基於文件儲存這一特性,使得儲存物件沒有像關係型資料庫有著約束。例如,當我們使用MySQL作為資料庫,當我們想要增加持久層Entity屬性時(所增加的屬性,必須儲存在資料庫的情況,除非所增加的屬性,不做為儲存,只是持久層Entity臨時的屬性),不得不為這個Entity所對應的表,增加欄位,否則所增加的屬性無法儲存,如果使用ORM框架,在對映過程中,還會出現異常。而MongoDB,使用BSON作為資料儲存格式,使得其沒有像關係型資料庫這樣較強的約束,在使用過程,持久層Entity可以隨時動態增加屬性,而MongoDB無需做任何更改。以下是Demo演示:

Demo工程地址:

https://github.com/faryang-sh/SpringDataJPALearning.git

實體定義:

@AllArgsConstructor
@Data
@ToString
public class Student {
    @Id
    private Long id;

    private String name;
    private Integer age;
    private School shool;

    //第二次執行單元測試加的
//    private String home;

}
@AllArgsConstructor
@Data
@Builder
@ToString
public class School {
    @Id
    private Long id;

    private String name;
    private String address;

}
Repository:
public interface SchoolReponsitory extends MongoRepository<School,Long> {
    School findSchoolByName(String name);
}
public interface StudentRepository extends MongoRepository<Student, Long> {
    Student findByName(String name);
}

單元測試:

第一次單元測試,Student沒有home屬性

	/**
	 * 第一次單元測試
	 * - student實體沒有加home屬性
	 *
	 * @throws Exception
	 */
	@Test
	public void insertStudentWithoutHome() throws Exception {
		School school1 = schoolReponsitory.findSchoolByName("南京路中學");
		School school2 = schoolReponsitory.findSchoolByName("北京路中學");

		studentRepository.save(new Student(1L, "小明", 30,school1));
		studentRepository.save(new Student(2L, "小紅", 40,school1));
		studentRepository.save(new Student(3L, "小王", 50,school2));
	}
第二次單元測試,Student有home屬性
	/**
	 * 第二次單元測試
	 * - student實體加home屬性
	 * @throws Exception
	 */
	@Test
	public void insertStudentWitHome() throws Exception {
		School school1 = schoolReponsitory.findSchoolByName("南京路中學");
		School school2 = schoolReponsitory.findSchoolByName("北京路中學");

		studentRepository.save(new Student(4L, "tom", 30,school1,"1小區"));
		studentRepository.save(new Student(5L, "peter", 40,school1,"2小區"));
		studentRepository.save(new Student(6L, "joy", 50,school2,"3小區"));
	}

結果:

第一次單元測試,MongoDB儲存結果:

第二次單元測試MongoDB儲存結果:


第一次單元測試,儲存的資料沒有home屬性,第二次單元測試前,為Student加上了home,使得儲存的資料具有home屬性,而在MongoDB層面,未做任何修改,說明,基於Spring Data JPA和MongoDB,可以實現Entity的動態增加。

在對儲存資料做查詢單元測試時,發現Entity屬性的增加亦或是缺失,對程式執行無影響。單元測試程式碼如下:

/**
	 * 對查詢結果列印
	 * 
	 */
	@Test
	public void findAll(){
		List<Student> students = studentRepository.findAll();
		students.forEach(student -> {
			System.out.println(student);
		});
	}
當Student沒有home屬性,列印結果:
Student(id=1, name=小明, age=30, shool=School(id=1, name=南京路中學, address=南京路))
Student(id=2, name=小紅, age=40, shool=School(id=1, name=南京路中學, address=南京路))
Student(id=3, name=小王, age=50, shool=School(id=2, name=北京路中學, address=北京路))
Student(id=4, name=tom, age=30, shool=School(id=1, name=南京路中學, address=南京路))
Student(id=5, name=peter, age=40, shool=School(id=1, name=南京路中學, address=南京路))
Student(id=6, name=joy, age=50, shool=School(id=2, name=北京路中學, address=北京路))

當Student有home屬性,列印結果:

Student(id=1, name=小明, age=30, shool=School(id=1, name=南京路中學, address=南京路), home=null)
Student(id=2, name=小紅, age=40, shool=School(id=1, name=南京路中學, address=南京路), home=null)
Student(id=3, name=小王, age=50, shool=School(id=2, name=北京路中學, address=北京路), home=null)
Student(id=4, name=tom, age=30, shool=School(id=1, name=南京路中學, address=南京路), home=1小區)
Student(id=5, name=peter, age=40, shool=School(id=1, name=南京路中學, address=南京路), home=2小區)
Student(id=6, name=joy, age=50, shool=School(id=2, name=北京路中學, address=北京路), home=3小區)
從結果上發現,Entity屬性增加和屬性,對程式執行無影響,影響的只是返回資料是否會缺失。

通過以上測試,說明Spring Data JPA對應MongoDB支援,在Entity屬性上,沒有想關係型資料庫那樣,具有較強的約束,框架對其只是做了屬性資料的對映,沒有校驗其資料欄位和Entity屬性是否一一對應,而這正是MongoDB儲存資料的特性所決定的。