You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
4.1 KiB

2 years ago
  1. /**
  2. * Our goal is to manage a Student class. Student has basic id, name and roll_number and one more thing:
  3. * vector of marks. Mark is a subentity with one to many relation. This example shows how to manage this kind of case.
  4. * First of all we got to understand how to keep data in the db. We need two tables: `students` and `marks`. Students
  5. * table has column equal to all Student class members exept marks. Marks table has two columns: student_id and value
  6. * itself. We create two functions here: inserting/updating student (with his/her marks) and getting student (also with
  7. * his/her marks). Schema is: `CREATE TABLE students (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL, roll_no
  8. * INTEGER NOT NULL)` `CREATE TABLE marks (mark INTEGER NOT NULL, student_id INTEGER NOT NULL)` One of the main ideas of
  9. * `sqlite_orm` is to give a developer ability to name tables/columns as he/she wants. Many other ORM libraries manage
  10. * subentities automatically and it is not correct cause developer must understand how everything works inside sqlite
  11. * otherwise his/her app might not work properly. Also developer must know schema in case he or she needs a strict
  12. * access with sqlite client.
  13. */
  14. #include <sqlite_orm/sqlite_orm.h>
  15. #include <iostream>
  16. using std::cout;
  17. using std::endl;
  18. class Mark {
  19. public:
  20. int value;
  21. int student_id;
  22. };
  23. class Student {
  24. public:
  25. int id;
  26. std::string name;
  27. int roll_number;
  28. std::vector<decltype(Mark::value)> marks;
  29. };
  30. using namespace sqlite_orm;
  31. auto storage =
  32. make_storage("subentities.sqlite",
  33. make_table("students",
  34. make_column("id", &Student::id, primary_key()),
  35. make_column("name", &Student::name),
  36. make_column("roll_no", &Student::roll_number)),
  37. make_table("marks", make_column("mark", &Mark::value), make_column("student_id", &Mark::student_id)));
  38. // inserts or updates student and does the same with marks
  39. int addStudent(const Student& student) {
  40. auto studentId = student.id;
  41. if(storage.count<Student>(where(c(&Student::id) == student.id))) {
  42. storage.update(student);
  43. } else {
  44. studentId = storage.insert(student);
  45. }
  46. // insert all marks within a transaction
  47. storage.transaction([&] {
  48. storage.remove_all<Mark>(where(c(&Mark::student_id) == studentId));
  49. for(auto& mark: student.marks) {
  50. storage.insert(Mark{mark, studentId});
  51. }
  52. return true;
  53. });
  54. return studentId;
  55. }
  56. /**
  57. * To get student from db we have to execute two queries:
  58. * `SELECT * FROM students WHERE id = ?`
  59. * `SELECT mark FROM marks WHERE student_id = ?`
  60. */
  61. Student getStudent(int studentId) {
  62. auto res = storage.get<Student>(studentId);
  63. res.marks = storage.select(&Mark::value, where(c(&Mark::student_id) == studentId));
  64. return res; // must be moved automatically by compiler
  65. }
  66. int main(int, char**) {
  67. decltype(Student::id) mikeId;
  68. decltype(Student::id) annaId;
  69. {
  70. storage.sync_schema(); // create tables if they don't exist
  71. Student mike{-1, "Mike", 123, {}}; // create student named `Mike` without marks and without id
  72. mike.marks = {3, 4, 5};
  73. mike.id = addStudent(mike);
  74. mikeId = mike.id;
  75. // also let's create another students with marks..
  76. Student anna{-1, "Anna", 555, {}};
  77. anna.marks.push_back(6);
  78. anna.marks.push_back(7);
  79. anna.id = addStudent(anna);
  80. annaId = anna.id;
  81. }
  82. // now let's assume we forgot about object `mike`, let's try to get him with his marks
  83. // assume we know `mikeId` variable only
  84. {
  85. auto mike = getStudent(mikeId);
  86. cout << "mike = " << storage.dump(mike) << endl;
  87. cout << "mike.marks = ";
  88. for(auto& m: mike.marks) {
  89. cout << m << " ";
  90. }
  91. cout << endl;
  92. auto anna = getStudent(annaId);
  93. cout << "anna = " << storage.dump(anna) << endl;
  94. cout << "anna.marks = ";
  95. for(auto& m: anna.marks) {
  96. cout << m << " ";
  97. }
  98. cout << endl;
  99. }
  100. return 0;
  101. }