Как стать автором
Обновить

Комментарии 38

В ActiveAndroid, как я погляжу, можно на уровне аннотаций задать имя поля, тогда можно использовать нормальные наименования для свойств класса, а имя поля задавать аннотациями.

А в других нельзя так? В OrmLite, например, если я на свойство name класса поставил DatabaseField, то в таблице необходимо, чтобы поле называлось именно так?

p.s. а вы сами используете какие-то ORM? Если бы речь шла о каком-то серверном приложении, то я бы не спрашивал, на клиенте просто редко сталкиваешься с ситуации, когда тонны данных записываются/читаются в SQLite.
В OrmLite можно. @DatabaseField(columnName="name") А так же множество других параметров — generatedId, index, unique, canBeNull, defaultValue, и т.д. и т.п.
Было бы интересно увидеть именно сравнение этих библиотек. Наличие/отсутствие каких-либо функций, по которым уже можно делать свой выбор. В частности для меня было критично то, что, например, ORMLite не умеет работать через ContentProvider. Планирую как-нибудь попробовать Сupboard, там, говорят, есть возможность работать через провайдер.
Когда появилась необходимость синхронизировать базу с облаком, сделал такую возможность в UCAOrm.
Сейчас будет имхо: полноценный ORM на мобильных устройствах — оверхед как по памяти, так и по производительности.

Как правило, достаточно просто библиотеки, которая обеспечивает вам уход от прямой работы с неудобным API ContentProvider и/или SQLiteDatabase.

И такие библиотеки есть:


BambooStorage мейтенится мной, используется в продакшене в нескольких приложениях, полет нормальный, есть мощные планы по 2.0 (постоение запросов через билдеры, поддержка SQLiteDatabase без ContentProvider, поддержка RxJava, compile-time генерация методов для парсинга/сериализации).

На данный момент оно предоставляет Collection-like API для хранения ваших «классов» в ContentProvider, при этом оверхед по производительности сведен к минимуму, по памяти — оверхеда вообще нет
storIOSQLite
  .get()
  .listOfObjects(Tweet.class)
  .withQuery(Tweet.ALL_TWEETS_QUERY)
  .withMapFunc(Tweet.MAP_FROM_CURSOR)
  .prepare()
  .createObservableStream() // here is the magic! It will be subscribed to changes in tables from Query
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Action1<List<Tweet>>() {
    @Override public void call(List<Tweet> tweets) {
      // display the data
      // magic: this will be called on each update in "tweets" table
    }
  });

Это конечно круто. Как понимаю внутри Callable interface?
А что на счет добавления группы записей?
В ContentProvider можно использовать bulkInsert для этого
 @Override
    public int bulkInsert(Uri uri, ContentValues[] values) {
    ...

Как у вас организовано?
Хорошо бы пример использования такого случая…
Тут такое дело:

1 — BambooStorage это теперь StorIO, 100% новый код, новый подход, релиз 1.0.0 уже скоро
2 — StorIO предоставляет API для работы как с SQLiteDatabase, так и с ContentResolver

Как понимаю внутри Callable interface?
не понял о чём конкретно вопрос :)

А что на счет добавления группы записей?
В ContentProvider можно использовать bulkInsert для этого


В StorIO есть три операции: Get, Put, Delete. На данный момент BulkInsert для ContentResolver к сожалению в такой подход вписывается плохо, т.к. гарантий, что конфликтов при записи в контент провайдер нет, перед вставкой, каждая запись проверяется: нет — insert, есть — update. Так что ответ пока такой — bulkInsert не поддерживается, возможно мы что-то предложим в будущем.
1000 записей добавить, через транзакцию делать самому?

dataBase.beginTransaction();
...
dataBase.insert
...
dataBase.setTransactionSuccessful();
dataBase.endTransaction();


И что будет с ContentObserver на курсоре. Именно bulkInsert решал проблему дергания 1000 раз в приведенном примере 1000 запросов

Встретил в ваших примерах знакомую конструкцию)
Подумал внутри что то подобное…

    public class DoTask implements Callable<Object> {
        public Object call() {
            return retDo;
        }
    }

StorIOSQLite конечно же поддерживает транзакции, но вот в случае с ContentProvider — вы не можете через ContentResolver начать транзакцию и вызывать insert, update, delete.

BulkInsert в ContentResolver, на мой взгляд, — хак, т.к. по сути его можно использовать только для своего контент провайдера, когда вы точно знаете что он пустой или что там таких записей нет и все значения успешно заинсертятся. Как правило, bulkInsert применяется для первоначального наполнения контент провайдера, но в таком случае это ваш контент провайдер и можно напрямую записать через транзакцию в SQLite если, конечно, в контент провайдере используется SQLite.

Когда мы обращаемся в чужой контент провайдер, у нас нет гарантий, что там нет таких же данных, bulkInsert в таком случае опасен.
Как правило, bulkInsert применяется для первоначального наполнения контент провайдера

Да именно это и имел в виду. Иногда надо небольшими пачками дописывать. Использовал действительно только в одном месте и был уверен
Даже скажу применил
long id = db.insertWithOnConflict(TABLE_NAME, null, value, SQLiteDatabase.CONFLICT_REPLACE);

Все же думаю попробовать UcaOrm
Подкупило описание на хабре из трех статей стэб бай стэп так сказать. Описано именно то что требовалось в проекте, а также сверх.
MIT лицензия!

вот в случае с ContentProvider — вы не можете через ContentResolver начать транзакцию и вызывать insert, update, delete.
Вы можете реализовать ContentProvider.applyBatch(ArrayList<ContentProviderOperation> operations), список operations — это ваши insert/update/delete, полученные с помощью ContentProviderOperation.new*(). В реализации поддерживайте транзакции и не вызывайте notifyChange когда не надо.
Да, можно реализовать applyBatch, это подойдёт для удаления множества записей, но Put Operation требует проверки на конфликт, соответственно, сначала нужно проверить есть ли такая запись, а затем сделать insert или update, StorIOContentResolver будет использовать applyBatch там, где это возможно
Проверка на конфликт не всегда нужна. Если вы используете ContentProvider поверх SQLite, то можно использовать
db.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_REPLACE), и это будет то же самое, только все проверки будет делать за вас SQLite. Всё, конечно, зависит от конкретного случая.
Да, согласен. Но insertWithOnConflict не всегда подходит, к сожалению. В StorIO можно определить свое поведение для каждого типа операций и использовать insertWithOnConflict, вместо query -> insert/update, например.
Я не сравниваю их, я оба ответа выше по треду просто говорил, что при использовании ContentProvider'a можно сделать так или этак.
public User() { }
public User(String username, String password,int age){ ... }
User johndoe = new User(getContext(),"john.doe","secret",19);
Зачем юзеру контекст?
Sugar вообще откровенно так себе написан: синглтон, SugarContext.init(context) приведет к мемори ликам, если передать туда не ApplicationContext и все такое. Разработчик еще пишет, что в Application.onTerminate() (который никогда не вызывается) нужно вызывать SugarContext.terminate(), более менее опытный человек бы такого не понаписал, конечно
А вы не поясните про мемори лики в синглтоне?
Конкретно в Sugar вызов SugarContext.init(context) с передачей в качестве контекста, например, Activity, вы получите постоянно удерживаемую сильную ссылку на эту Activity, соответственно, GC не сможет освободить память, связанную с данной Activity, пока есть хоть одна сильная ссылка на нее.

Правильным решением, со стороны Sugar, было бы вызывать context.getApplicationContext() при сохранении ссылки в SugarContext, к тому же, это бы дало runtime проверку на передачу null в качестве контекста.
Спасибо большое
Если в библиотеке написано
context.getApplicationContext()
все будет ок.
Собственно, я об этом и написал, в SugarContext.init(context) ссылка на context сохраняется как есть
Точно. Не обратил внимания, виноват.
Смею предположить, что там доступ к ресурсам нужен будет…
Окей, но я не зря привел конструкторы класса User. Этот код не скомпилится.
А слона то я и не заметил =/
Realm не является ORM, он даже не использует SQLite. Это написанная с нуля NoSql база.
Фраза " Realm написан на С++ и запускается прямо на вашем устройстве (без интерпретации), что обеспечивает очень высокую производительность" вообще не понятна, все ORM как бы запускается на устройстве.

А кто-то использовал ORM вместе с Kotlin? Завести Realm не получилось из-за его особенности процессинга аннотаций и требований к классам модели.
Перешел на Realm, работает быстро, писать просто. Жду когда введут запросы на ссылки.
В 0.72 уже появились:
We just released Realm Java 0.72.0 to this website and to Maven. It includes support for Eclipse, Link Queries, Sorting on more field types, Transaction Rollback and more!

realm.io/news/
Почему не использовать встраиваемые объектные БД? вроде db4o. Минус один уровень абстрагирования
Наконец все идет к тому, что дизайн — это прежде всего удобство пользования (или если хотите — юзабилити), а не оформление и эффекты.
«создание запросов — занятие скучное и ленивое» — не согласен. Я даже немного скучаю по былым временам девелопинга под 1cv8, когда многие алгоритмы строятся с использованием запросов, составление которых порой превращается в хитромудрый квест, делающих до 70-80% работы алгоритма.
Это не БД, это просто XML файлы в определённой директории. Несвязный набор пар ключ-значение. При чем тут ORM?
Внесу свою лепту к этой статье: я бы не советовал использовать любые ОРМ в тех случаях, если у вас огромные наборы данных и вложенные коллекции больше 2х уровней. Выборка большого количества данных ужасно медленно работает.
Также, как сказал товарищ выше, ORMLite не умеет работать с ContentProvider, поэтому приходится искать обходные пути.
Перепробовав все ORM на Android я выбрал для себя следующий набор для работы с БД:
1: ProviGen — для генерации CP и SQLiteOpenHelper на базе контракта.
2: Cupboard — для удобного построения запросов и cursor to object преобразований.
Не знаю как вы, но я использую в играх для мобил лучший ORM (с поддержкой MongoDB/Membase и кучей других хранилищ данных) Spring Data projects.spring.io/spring-data/

1. Простотота
2. Скорость
3. Отсутвие велосипедов

Если есть время изучать велосипеды с синтаксическим сахором, ради бога. Но я более-менее выбираю «стандарт»
Зарегистрируйтесь на Хабре, чтобы оставить комментарий