МЕЖДУНАРОДНЫЙ НАУЧНЫЙ ЖУРНАЛ «СИМВОЛ НАУКИ» №6/2016 ISSN 2410-700Х
5. Ожегов, С. И. Толковый словарь русского языка / С. И. Ожегов, Н. Ю. Шведова. - М.: Азбуковник, 2000. - 940 с.
6. Пушников А.Ю. Введение в системы управления базами данных. Часть 1. Реляционная модель данных: Учебное пособие/Изд-е Башкирского ун-та. - Уфа, 1999. - 108 с. - ISBN 5-7477-0350-1
© Поддубная Л.В., 2016
УДК 004.9:519.688
Смольянов Андрей Григорьевич
к.ф.-м.н., зав. кафедрой фундаментальной информатики ФГБОУ ВО «МГУ им. Н.П. Огарёва»,
г. Саранск, РФ E-mail: [email protected] Ивановичев Вячеслав Валерьевич студент 4 курса факультета математики и информационных технологий ФГБОУ ВО «МГУ им. Н.П. Огарёва»,
г. Саранск, РФ E-mail: [email protected]
МАНИПУЛЯЦИЯ ДАННЫМИ В МОБИЛЬНОЙ СУБД REALM ДЛЯ GOOGLE ANDROID
Аннотация
В статье описываются возможности манипулирования данными, организованными системой управления базами данных (СУБД), предназначенной для поддержки информационной части мобильных приложений. В статье кратко описываются разновидности операций, связанной с доступом к исходным данным и их обработкой.
Ключевые слова
Система управления базами данных, класс, объект, запрос, асинхронная транзакция.
В статье [1] были изложены вводные сведения о системе управления базами данных Realm. Настоящий материал является продолжением указанной статьи, в котором продолжено краткое обсуждение возможностей Realm, связанных с манипулированием данными в базе.
Для обзора основных возможностей по манипулированию данными кратко обсудим сам механизм запросов. Синтаксис запросов Realm использует так называемый Fluent Interface (пер. Текучий интерфейс), суть которого состоит в повышении читабельности исходного кода программы. Благодаря этому код запросов становится лаконичным и интуитивно понятным. Структура запросов выглядит следующим образом:
(экземпляр Realm).(критерий where).
(условия выборки).(fmdFirstO или findAll()).
Метод findFirst() дает возможность обнаружить в процессе запроса первое совпадение, метод findAll() позволяет получить полную выборку. Если по нужным условиям не удалось найти данные, то findFirst() вернет null, а findAll() - пустую коллекцию RealmResults.
Например, для того выбрать из Realm пользователя (класс User), чье имя совпадает с именем "Александр", достаточно написать код:
_МЕЖДУНАРОДНЫЙ НАУЧНЫЙ ЖУРНАЛ «СИМВОЛ НАУКИ» №6/2016 ISSN 2410-700Х_
User user = realm.where(User.class)
.equalTo("name", "Александр")
.findFirst();
Переменная user содержит объект пользователя со всеми его данными. Теперь для получения списка заметок используется геттер:
RealmList<Note> notes = user.getNotes(); Результат выборки показан на рисунке 1.
,.|| 100% И 14:15
RealmNotes
Александр 1
Заметка 1 Александра Fri Feb 19 12:29:20 GMT+03:00 2016
2
Заметка 2 Александра Fri Feb 19 12:29:20 GMT+03:00 2016
Рисунок 1 - Результат выборки данных
Другой вариант выборки не обращаться к связной модели, а напрямую выполнить следующий код, результат которого полностью эквивалентен предыдущему: RealmResults<Note> notes = realm.where(Note.class).equalTo("user.name", "Александр").findAllO;
Этот запрос означает следующее: выбрать из Realm все заметки (класс Note), в которых в связной модели (класс User) имя совпадает с именем "Александр". Кроме того, результатом данной выборки будет коллекция RealmResults, которая является подклассом Java-класса AbstractList и хранит ссылки на объекты Notes. Заметим важный факт: Realm не копирует выбранные объекты, а возвращает ссылки на оригинальные объекты из хранилища.
Чтобы достать заметки Вячеслава, следует всего лишь изменить имя в методе .equalTo(); User user = realm.where(User.class) .equalTo("name", "Вячеслав") .findFirst();
Для того чтобы добавить больше заметок пользователю "Вячеслав" (на данный момент 2 заметки), требуется открыть транзакцию с помощью метода beginTransaction(), выполнить добавление данных, применить транзакцию с помощью метода commitTransaction(): realm.beginTransaction(); try {
User user = realm.where(User.class) .equalTo("name", "Вячеслав") .findFirst(); int lastId =
_МЕЖДУНАРОДНЫЙ НАУЧНЫЙ ЖУРНАЛ «СИМВОЛ НАУКИ» №6/2016 ISSN 2410-700Х_
realm.where(Note.class).findAll().max("id").intValue()
+ 1;
if (user.getNotes() != null) {
RealmList<Note> notes = user.getNotes();//количество 2 for (int i = 1; i <= 10; i++) { Note note = new Note(); note.setId(lastId + i); note.setDate(new Date()); note.setUser(user); note.setTitle (" Заметка Вячеслава"); note = realm.copyToRealm(note); notes.add(note);
}
realm.commitTransaction(); user.getNotes(); // количество 12
}
txtName.setText(user.getName()); } catch (Exception e) { e.printStackTrace(); realm.cancelTransaction();
}
Результат работы данного кода показан на рисунке 2.
Заметка 1 Вячеслава Заметка 2 Вячеслава Заметка Вячеслава Заметка Вячеслава
Рисунок 2 - Результат добавления данных
Заметить, что в данном коде бы использован так называемый агрегирующий метод - max(), предназначенный в нашем случае для выборки максимального id.
Realm позволяет использовать следующие агрегирующие методы:
_МЕЖДУНАРОДНЫЙ НАУЧНЫЙ ЖУРНАЛ «СИМВОЛ НАУКИ» №6/2016 ISSN 2410-700Х_
1. results.sum("Поле").intValue()- сумма;
2. results.max("Поле").longValueO- максимальный элемент;
3. results.min("Поле").longValueO- минимальный элемент;
4. double average = results.average("Поле") - среднее;
5. results.matches()- количество совпадений.
Помимо .equalTo() Realm поддерживает следующие условия:
• between, greaterThan(), lessThan(), greaterThanOrEqualTo() & lessThanOrEqualTo()
• equalTo() & notEqualTo()
• contains(), beginsWith() & endsWith()
Строковые условия по умолчанию чувствительны к регистру, чтобы сделать условия не чувствительными к регистру нужно добавить модификатор CASE_INSENSITIVE.
К примеру, выберем те заметки, у которых дата публикации между 19 и 24 февраля 2016 года. GregorianCalendar calendar = new GregorianCalendar(); calendar.set(2016, Calendar.FEBRUARY, 18); Date dateMin = calendar.getTime(); calendar.set(2016, Calendar.FEBRUARY, 24); Date dateMax = calendar.getTime(); RealmResults<Note> n = realm.where(Note.class) .between("date",dateMin,dateMax) .findAll();
Результат выполнения кода показан на рисунке 3.
Заметки между 19 и 24 февраля
Заметка 2 Александра Fri Feb 19 17:45:34 GMT+03:00 2016
3
Заметка 1 Вячеслава Fri Feb 19 17:45:34 GMT+03:00 2016
4
Заметка 2 Вячеслава Fri Feb 19 17:45:34 GMT+03:00 2016
5
Заметка 1 Михаила_
Рисунок 3 - Результат выборки данных
Важное замечание: по умолчанию условия в Realm, соединенные точкой, соответствуют логической операции "И". Для того чтобы использовать "ИЛИ", условия следует объединять в группу, факторизованную скобками. Добавим к вышепоказанному примеру ограничения: выберем лишь те заметки, которые относятся к Александру или Михаилу, отсортируем их по id в порядке убывания, а интервал дат оставим прежним. Следующий код решает эту задачу.
_МЕЖДУНАРОДНЫЙ НАУЧНЫЙ ЖУРНАЛ «СИМВОЛ НАУКИ» №6/2016 ISSN 2410-700Х_
GregorianCalendar calendar = new GregorianCalendar(); calendar.set(2016, Calendar.FEBRUARY, 18); Date dateMin = calendar.getTime(); calendar.set(2016, Calendar.FEBRUARY, 24); Date dateMax = calendar.getTime(); RealmResults<Note> n = realm.where(Note.class) .between("date", dateMin, dateMax) .beginGroup()
.equalTo("user.name", "Александр") or()
.equalTo("user.name", "Михаил") .endGroup() .findAll(); n.sort("id", Sort.DESCENDING);
В приведенном выше коде условие "ИЛИ" отделяется .beginGroup() и .endGroup(), что можно интерпретировать как операторные скобки. Результат работы кода показан на рисунке 4.
Заметки между 19 и 24
февраля
5
Заметка 1 Михаила Fri Feb 19 17:45:34 GMT+03:00 2016 2
Заметка 2 Александра Fri Feb 19 17:45:34 GMT+03:00 2016
1
Заметка 1 Александра Fri Feb 19 17:45:34 GMT+03:00 2016
Рисунок 4 - Результат выборки данных
Особо отметим коллекцию RealmResults<?>. Её преимущество состоит в том, что при изменении данных у моделей из этой коллекции запрос на получение обновленных значений писать не требуется заново - они обновляются на лету.
Кратко обсудим возможности асинхронных запросов.
По аналогии с асинхронной записью Realm поддерживает выборку данных в отдельном потоке. Как правило, запросы выполняются очень быстро, так что в простых случаях запросы можно запускать из UI потока. Для случаев, когда требуется построить сложный запрос с большой выборкой данных, использование отдельных потоков вполне оправдано. Например, следующий код выполнит выборку в отдельном потоке, а затем вернет полученные данные в главный поток: RealmResults<User> result = realm.where(User.class).findAllAsync();
_МЕЖДУНАРОДНЫЙ НАУЧНЫЙ ЖУРНАЛ «СИМВОЛ НАУКИ» №6/2016 ISSN 2410-700Х_
Если требуется получить уведомление об успешном получении данных из другого потока, необходимо зарегистрировать слушатель RealmChangeListener и передать его в метод .addChangeListener(). Этот слушатель будет вызываться каждый раз когда объект RealmResults будет обновлен. К примеру, достанем все заметки и выведем их в ListView в виде - <заголовок заметки> <Автор>: ListView notesList = (ListView) findViewById(R.id.notesList); final Context context = this; RealmChangeListener callback =
new RealmChangeListener() { @Override
public void onChange() {
Toast.makeText(context, "Данные успешно получены",Toast.LENGTH_LONG) .show();
}
};
RealmResults<Note> result = realm.where(Note.class).findAllAsync();
result.addChangeListener(callback);
notesList.setAdapter
(new NotesAdapter(context, result)); Результат работы кода показан на рисунке 5.
Заметка 1 Вячеслава Вячеслав
Заметка 2 Вячеслава Вячеслав
Заметка 1 Михаила Михаил
За
Данные успешно получены
IVICI Г\ CI unlcCTlaDCl
Вячеслав
Рисунок 5 - Результат асинхронного запроса
Слушатель описывается с помощью метода
result.removeChangeListeners().
Отписаться от нужного слушателя позволяет метод
result.removeChangeListener(callback).
Удаление данных, как при выполнении записи в Realm, необходимо оборачивать в методы beginTransaction и commitTransaction(). Существуют несколько методов удаления данных из базы данных. К примеру, достанем из базы данных все заметки и применим к ним эти методы: RealmResults<Note> results =
realm.where(Note.class) .findAll(); В этих условиях:
1. results.removeLast()- удалит последний элемент коллекции RealmResults;
2. results.remove(0) - удалит элемент с индексом 0, т. е. первый элемент коллекции;
3. results.clear()- удалит все выбранные из базы данных объекты.
_МЕЖДУНАРОДНЫЙ НАУЧНЫЙ ЖУРНАЛ «СИМВОЛ НАУКИ» №6/2016 ISSN 2410-700Х_
4. note.removeFromRealm()- удалит объект из БД.
Исходя из рассмотренных основных возможностей данной системы управления базами данных, можно сделать вывод о том, что Realm является весьма мощным, быстрым и простым в использовании инструментом для разработки мобильных приложений любой сложности и тематической направленности.
Список использованной литературы 1. Смольянов А.Г., Ивановичев В. В. Краткий обзор мобильной СУБД Realm для Google Android. // Международный научный журнал «Символ науки». - 2016. - часть 4. - № 3. - с. 35-40.
© Смольянов А. Г., Ивановичев В. В., 2016