Я просмотрел множество руководств и примеров того, как реализовать Sqflite во Flutter. Все остальные примеры выполняются с использованием только одной модели или таблицы базы данных. Как определено в этих руководствах:
https://pub.dartlang.org/packages/sqflite
https://www.developerlibs.com/2018/07/flutter-sqlite-database-example.html
http://camposha.info/flutter/sqflite-insert-select-show
Насколько я понял, нам нужно создать столько моделей и помощников, сколько таблиц. Для каждой таблицы базы данных будет файл model.dart и файл helper.dart.
У меня вопрос, могу ли я иметь только одного помощника для всех моделей?
ОБНОВИТЬ
В файле helper.dart есть будущая «вставка». Как я могу использовать одну и ту же фурнитуру для всех моделей?
Future<Todo> insert(Todo todo) async {
todo.id = await db.insert(tableTodo, todo.toMap());
return todo;
}
Спасибо @pskink, это было быстро. Пожалуйста, просмотрите мой вопрос, так как есть обновление.
я понятия не имею, что вы на самом деле имеете в виду под «одинаковое будущее для всех моделей»
может быть, OP означал, что он хочет определять модели, и фреймворк будет автоматически читать или сохранять эти модели / объекты в базе данных Sqflite - может быть, своего рода Flutter Sqflite Hibernate?
и как-то отвечая на вопрос, это можно было бы использовать с помощью метаданных / аннотаций, но я бы лично от этого сбежал. :) Я быстро поискал об этом и не нашел ни одного пакета, преследующего эту цель.
Я сделал несколько комментариев, советуя обратное, но я просто вспомнил, что в моем последнем проекте я делал что-то подобное, это было для База данных Firebase, но это было бы очень похоже на sqflite.
Я создал абстрактный класс BaseItem
с key
, и все модели будут производными от этого класса.
Я также создал абстрактный класс BaseProvider
, который потребовал бы BaseItem и определил бы простые методы для доступа к модели.
Методы upsert
и delete
лежат в FirebaseBaseProvider
, который расширяет BaseProvider
.
Я вставлю сюда его части (убрав довольно много, чтобы было понятнее):
abstract class BaseItem {
const BaseItem({this.key});
final String key;
}
abstract class BaseProvider<T extends BaseItem> {
Future<List<T>> find();
Future<BaseKey> upsert(T item);
Future<int> delete(T item);
}
abstract class FirebaseBaseProvider<T extends BaseItem> {
// Abstract methods which need to be implemented
T fromMap(BaseKey key, dynamic map);
Map<String, dynamic> toJson(BaseKey key, T item);
Future<DatabaseReference> getReference(BaseKey base) async { ... }
BaseKey compileKey(T item, {String useKey}) { ... }
Future<List<T>> find() async {
List<T> result = new List();
// my implementation doesnt work like this,
// as it's firebase based, but this would
// be the place in a Sqflite implementation to use
// fromMap and load the items
return result;
}
Future<BaseKey> upsert(T item) async {
if (item == null) return null;
BaseKey key = compileKey(item);
(await getReference(key)).set(toJson(key, item));
return key;
}
Future<int> delete(T item) async {
if (item == null) return null;
if (item.key != null && item.key != "") {
(await getReference(compileKey(item))).remove();
}
return 0;
}
}
Затем, чтобы реализовать модель News
или любую другую модель, я бы создал ее, просто определив ее содержимое, например:
class News extends BaseItem {
News({String key, this.creation, this.messageSubject, this.messageBody}) : super(key: key);
final DateTime creation;
final String messageSubject;
final String messageBody;
bool operator ==(o) => o is News && (o.key == key);
int get hashCode => key.hashCode;
}
И для этого потребуется его конкретный провайдер, который будет реализовывать только методы toJson
и fromMap
, например:
class NewsProvider extends FirebaseBaseProvider<News> {
@override
Map<String, dynamic> toJson(BaseKey key, News news) {
return {
"creation": news.creation,
"messageSubject": news.messageSubject,
"messageBody": news.messageBody,
};
}
@override
News fromMap(BaseKey key, dynamic map) {
DateTime creation = map["creation"] == null ? null : DateTime.tryParse(map["creation"] as String);
return new News(
key: key.child.key,
creation: creation,
messageSubject: map["messageSubject"] as String,
messageBody: map["messageBody"] as String,
);
}
}
В конце концов, NewProvider
предоставляет методы find
, upsert
и delete
, но их реализация лежит в абстрактном классе, всего в одной их реализации для всех моделей, как вы хотели.
Конечно, моя реализация намного сложнее, потому что Firebase требует другого подхода для получения / загрузки элементов, а также из-за того, что метод find
в конечном итоге должен быть разным в каждой конкретной модели поставщика. Но все же можно упростить довольно много.
В комментарии я сказал, что этот последний класс, конкретный NewsProvider
, который имеет конкретные реализации как toJson
, так и fromMap
, также может быть обобщен с помощью аннотаций в классе модели News
, но это приносит довольно много проблем и неясностей и - на мой взгляд конечно - не стоит.
У меня был аналогичный вопрос о создании таблиц, все примеры просто создают одну таблицу. Я нашел этот страница в Интернете, который создал две таблицы, помещая ожидание для каждой команды.
Нравится:
Future _onCreate(Database db, int version) async {
await db.execute("CREATE TABLE table1 (id INTEGER, valuex TEXT)");
await db.execute("CREATE TABLE table2 (id INTEGER, valuey TEXT)");
await db.execute("CREATE TABLE table3 (id INTEGER, valuez TEXT)");
}
в
openDatabase
у вас есть параметрonCreate
- используйте его для создания любого количества таблиц - см._onCreate
здесь