БД имеют неприятную особенность, когда нужно создавать множество запросов, контролировать связи, формировать все вручную. Для облегчения жизни программиста есть ORM (Object Relation Mapping).
В данном уроке мы познакомимся с такой библиотекой как ORMLite. Эта библиотека позволяет создать представление таблиц и их отношений в виде обычных классов. Таким образом, мы уйдем от написания тяжелый и затрудняющих чтение и понимание классов к управлению объектами.
Шаг 1
Начнем с поставления задачи. На картинке ниже представлено 3 класса. 2 с них находятся внутри 1 (Question). Такой тип связи называется агрегацией. Создадим такие ж 3 таблички в базе и свяжем их между собой. Category – Question , Answer – Question
Шаг 2
На протяжении урока будем использовать базу SQLite. Создаем ее с помощью специального ПО. Можно использовать Navicat или другие подобные программы для работы с базой. Я буду использовать плагин для Firefox -> SQLite Manager. Создаем базу под именем main.sqlite. Создаем таблички:
Создание таблички question:
CREATE TABLE "main"."question" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "category" INTEGER, "text" VARCHAR, "img" VARCHAR)
Создание таблички category:
CREATE TABLE "main"."category" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "name" VARCHAR)
Создание таблички answer:
CREATE TABLE "main"."answer" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "id_q" INTEGER, "value" VARCHAR, "correct" BOOL)
Шаг 3
После создания табличек, их нужно заполнить данными. Заполним полноценных 2 объекта. 1 question, 1 category, 2 answer.
category:
INSERT INTO "main"."category" ("name") VALUES ("category1") INSERT INTO "main"."category" ("name") VALUES ("category2")
question:
INSERT INTO "main"."question" ("category","text","img") VALUES (1,"One?","Not img now"); INSERT INTO "main"."question" ("category","text","img") VALUES (2,"Four?","Not img now");
answer:
INSERT INTO "main"."answer" ("id_q","value","correct") VALUES (1,"One","1"); INSERT INTO "main"."answer" ("id_q","value","correct") VALUES (1,"Two","0"); INSERT INTO "main"."answer" ("id_q","value","correct") VALUES (2,"Three","0"); INSERT INTO "main"."answer" ("id_q","value","correct") VALUES (2,"Four","1");
Шаг 4
Теперь создадим соответствующие классы в нашем проекте. Классы должны содержать сеттеры, геттеры и конструктор по умолчанию.
Question:
package org.knowledgechecker.entity; import java.util.List; public class Question { private int id; private Category category; private String text; private String img; private List<Answer> answers; public Question() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public Category getCategory() { return category; } public void setCategory(Category category) { this.category = category; } public String getText() { return text; } public void setText(String text) { this.text = text; } public String getImg() { return img; } public void setImg(String img) { this.img = img; } public List<Answer> getAnswers() { return answers; } @Override public String toString() { return "Question{" + "id=" + id + ", category=" + category + ", text='" + text + '\'' + ", img='" + img + '\'' + ", answers=" + answers + '}'; } public void setAnswers(List<Answer> answers) { this.answers = answers; } }
Category:
package org.knowledgechecker.entity; public class Category { private int id; private String name; public Category() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Category{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
Answer:
package org.knowledgechecker.entity; public class Answer { private int id; private Question question; private String value; private boolean correct; public Answer() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public Question getQuestion() { return question; } public void setQuestion(Question question) { this.question = question; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public boolean isCorrect() { return correct; } public void setCorrect(boolean correct) { this.correct = correct; } @Override public String toString() { return "Answer{" + "id=" + id + ", idQuestion=" + idQuestion + ", value='" + value + '\'' + ", corect=" + corect + '}'; } }
Шаг 5
Подключаем нашу библиотеку ORMLite. Ее можно взять с офф. сайта по ссылке: http://ormlite.com/releases/ или, подключить с помощью Maven.
<dependency> <groupId>com.j256.ormlite</groupId> <artifactId>ormlite-core</artifactId> <version>4.47</version> </dependency> <dependency> <groupId>com.j256.ormlite</groupId> <artifactId>ormlite-jdbc</artifactId> <version>4.47</version> </dependency> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.7.2</version> </dependency>
Для того чтобы проверять правильность настройки можно использовать библиотеку Junit:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency>
Шаг 6
Подключив библиотеки, приступаем к аннотированию классов, чтобы определить их связи.
Category:
@DatabaseTable public class Category { @DatabaseField(generatedId = true) private int id; @DatabaseField private String name; //getters and setters... }
@DatabaseTable – для указание на табличку с базы.
tableName – eсли имя класса не совпадает с именем таблички
@DatabaseField – указывает что поле является столбцом.
columnName – указать имя колонки самостоятельно. (Если имя колонки не совпадает с именем поля класса)
Id – поле является идентификатором
generatedId – идентификатор генерируется автоматиески
foreign – ссылается на другой класс, который также хранит в себе таблицу
Answer:
@DatabaseTable (tableName = "answer") public class Answer { @DatabaseField(generatedId = true) private int id; @DatabaseField(columnName = "id_q", foreign = true) private Question question; @DatabaseField private String value; @DatabaseField private boolean correct; //getter and setters... }
Question:
@DatabaseTable(tableName = "question") public class Question { @DatabaseField(generatedId = true) private int id; @DatabaseField(columnName = "category", foreign = true) private Category category; @DatabaseField private String text; @DatabaseField private String img; @ForeignCollectionField private ForeignCollection<Answer> answers; //getters and setters }
Обратите внимание, что в 13 строке был изменен List на ForeignColliection<Answer>.
@ForeignCollectionField – получает коллекцию данных зависимой таблички.
Шаг 7
После создания сущностей и связывания их с табличками в БД создаем сервис, для управления их поведением. ORMLite дает легкий способ создания DAO (Data Accsess Object) который мы используем для построения нашего сервиса. Чтобы урок не разростался и дальше, приведу код одного из сервиса.
public class QuestionService { private final String url = "jdbc:sqlite:main.sqlite"; private ConnectionSource source; private Dao<Question, String> dao; public QuestionService() throws SQLException { source = new JdbcConnectionSource(url); dao = DaoManager.createDao(source,Question.class); } public List<Question> getAll() throws SQLException { return dao.queryForAll(); } }
url – путь к нашей бд
source = new JdbcConnectionSource(url) – создаем подключение к нашей базе по url
dao = DaoManager.createDao(source,Question.class) – создание DAO для класса. Он будет использоваться
для того чтобы управлять объектом, выполнять над ним операции чтения, сохранения, удаления, изменения и т.д в базе.
dao.queryForAll() – возвращает все данные с таблички query и зависимых табличек.
Пример выполнения метода getAll() с тестового набора для класса Questions:
1 – это лог наших запросов, информация о работе библиотеки
2 – наш результат, который мы ждали. вывод с таблички answer есть корректным. Для вывода его в “человеческом” виде, достаточно сделать обработку этой коллекции.
В заключение, можно выполнять аналогичным образом операции CRUD (Create Read Update Delete), а также, есть пара дополнительных методов, которые добавят возможностей. Об этом, по необходимости, в следующем уроке.
Спасибо.
ПОХОЖИЕ ПУБЛИКАЦИИ
- None Found
6 комментариев к статье "Java SQLite ORM"