Многостоловые модели Flutter Sqflite

Я просмотрел множество руководств и примеров того, как реализовать 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;
}

в openDatabase у вас есть параметр onCreate - используйте его для создания любого количества таблиц - см. _onCreateздесь

pskink 05.12.2018 11:59

Спасибо @pskink, это было быстро. Пожалуйста, просмотрите мой вопрос, так как есть обновление.

Zain SMJ 05.12.2018 12:17

я понятия не имею, что вы на самом деле имеете в виду под «одинаковое будущее для всех моделей»

pskink 05.12.2018 12:37

может быть, OP означал, что он хочет определять модели, и фреймворк будет автоматически читать или сохранять эти модели / объекты в базе данных Sqflite - может быть, своего рода Flutter Sqflite Hibernate?

Feu 06.12.2018 14:20

и как-то отвечая на вопрос, это можно было бы использовать с помощью метаданных / аннотаций, но я бы лично от этого сбежал. :) Я быстро поискал об этом и не нашел ни одного пакета, преследующего эту цель.

Feu 06.12.2018 14:24
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
5
4 597
2

Ответы 2

Я сделал несколько комментариев, советуя обратное, но я просто вспомнил, что в моем последнем проекте я делал что-то подобное, это было для База данных 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)");
    }

Другие вопросы по теме