Ответ
В моих Flutter-проектах я работал с реляционными базами данных в основном для локального хранения структурированных данных. Основной инструмент — SQLite, так как он встроен в мобильные платформы.
1. Работа с SQLite через sqflite:
Это самый распространённый пакет для прямого выполнения SQL-запросов.
import 'package:sqflite/sqflite.dart';
class DatabaseHelper {
Future<Database> initDB() async {
return openDatabase(
'app.db',
version: 1,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE Notes(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
created_at INTEGER
)
''');
},
);
}
Future<int> insertNote(Note note) async {
final db = await initDB();
return await db.insert('Notes', note.toMap());
}
Future<List<Note>> getNotes() async {
final db = await initDB();
final List<Map<String, dynamic>> maps = await db.query('Notes');
return List.generate(maps.length, (i) => Note.fromMap(maps[i]));
}
}
2. Использование ORM (Object-Relational Mapping):
Для более сложных проектов я применял floor или moor (теперь drift). Они генерируют типобезопасный код из аннотаций Dart-классов, что уменьшает количество шаблонного кода и ошибок.
// Пример с floor (аннотации)
@Entity(tableName: 'notes')
class Note {
@PrimaryKey(autoGenerate: true)
final int? id;
final String title;
...
}
@dao
abstract class NoteDao {
@Query('SELECT * FROM notes')
Future<List<Note>> getAllNotes();
@insert
Future<void> insertNote(Note note);
}
3. Работа с серверными СУБД:
Для взаимодействия с удалёнными базами (PostgreSQL, MySQL) я использовал REST или GraphQL API, написанные на бэкенде (например, на Node.js или Dart с shelf/aqueduct), и получал данные в формате JSON.
Мой опыт включает проектирование схемы БД, миграции, оптимизацию запросов (использование индексов) и интеграцию реактивного состояния приложения (например, через Stream из drift) с UI Flutter.
Ответ 18+ 🔞
А, ну вот, про базы данных! Ты знаешь, это как с машиной: можно ездить на старенькой «девятке», где всё руками, а можно на новом авто с кучей автоматики. Но в итоге и там, и там — из точки А в точку Б, просто комфорт разный, ёпта.
1. SQLite через sqflite: классика, как гаражный ремонт.
Это когда ты сам всё паяешь, провода перекидываешь, и если накосячил — сам и расхлёбываешь. Прямые SQL-запросы, открыл базу, создал таблицу — всё честно, но и ответственность полная. Один неверный JOIN — и приложение накрылось медным тазом.
import 'package:sqflite/sqflite.dart';
class DatabaseHelper {
Future<Database> initDB() async {
return openDatabase(
'app.db',
version: 1,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE Notes(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
created_at INTEGER
)
''');
},
);
}
Future<int> insertNote(Note note) async {
final db = await initDB();
return await db.insert('Notes', note.toMap());
}
Future<List<Note>> getNotes() async {
final db = await initDB();
final List<Map<String, dynamic>> maps = await db.query('Notes');
return List.generate(maps.length, (i) => Note.fromMap(maps[i]));
}
}
Честно, иногда так и хочется сказать — ёб твою мать, сколько же шаблонного кода! Каждый раз одно и то же: открыть, выполнить, закрыть. Но зато контроль полный, как у сапёра: ошибешься один раз — и будет вам хиросима и нигерсраки.
2. ORM типа floor или drift: пересадка на автомобиль с автопилотом.
Тут уже не надо самому SQL-запросы городить. Написал класс, навесил аннотации — и система сама за тебя всё сгенерирует. Красота же! Типобезопасность, меньше шансов накосячить. Хотя, если ORM криво сгенерирует запрос — удивление пиздец, отладка потом — это отдельный вид искусства.
// Пример с floor (аннотации)
@Entity(tableName: 'notes')
class Note {
@PrimaryKey(autoGenerate: true)
final int? id;
final String title;
...
}
@dao
abstract class NoteDao {
@Query('SELECT * FROM notes')
Future<List<Note>> getAllNotes();
@insert
Future<void> insertNote(Note note);
}
Смотри, какая магия: написал getAllNotes() — и всё, да похуй, как оно там внутри работает. Главное — результат приходит. Но доверия ебать ноль к этим генераторам на первых порах, всё время кажется, что они где-то налажают.
3. Серверные СУБД (PostgreSQL, MySQL): тут уже игра в команде. Твоё Flutter-приложение — это только фасад. Вся основная логика и данные живут на сервере. Ты шлёшь запросы по REST или GraphQL, а в ответ получаешь JSON. Задача — красиво это отобразить и отправить обратно, если что.
Опыт включает в себя всё: от проектирования схемы («а где тут связи, бля?») до миграций («ой, надо поле добавить, а в продакшене уже овердохуища записей»). Оптимизация запросов — это отдельная песня. Без индексов на больших таблицах терпения ноль ебать, всё виснет, как будто на дворе 2002-й год.
А самое крутое — это когда реактивное состояние из базы (тот же Stream из drift) цепляешь к UI. Данные сами обновляются на экране, когда что-то меняется в таблице. Выглядит волшебно, но под капотом — хитрая жопа из стримов и подписок, которую тоже надо уметь правильно собрать.
В общем, инструмент выбирается под задачу. Иногда проще хуй с горы — написать прямой запрос и не париться. А для большого проекта лучше взять ORM, чтобы не сойти с ума от этого однообразного кода. Главное — понимать, что ты делаешь, а не просто копипастить из документации.