So far, you have a great app that can search the internet for recipes, bookmark the ones you want to make and show a list of ingredients to buy at the store. But what happens if you close the app, go to the store and try to look up your ingredients? They’re gone! As you might have guessed, having an in-memory repository means that the data doesn’t persist after your app closes.
One of the best ways to persist data is with a database. Both Android and iOS provide access to the SQLite database system. This allows you to insert, read, update and remove structured data that are persisted on disk.
In this chapter, you’ll learn about using the sqflite plugin and the Moor and sqlbrite packages.
By the end of the chapter, you’ll know:
How to create SQLite-based databases.
How to insert, fetch and remove recipes or ingredients.
How to use the sqflite plugin.
How to use the sqlbrite library and receive updates via streams.
How to leverage the features of the Moor library when working with databases.
Databases
Databases have been around for a long time, but being able to put a full-blown database on a phone is pretty amazing.
What is a database? Think of it like a file cabinet that contains folders with sheets of paper in them. A database has tables (file folders) that store data (sheets of paper).
Database tables have columns that define data, which is then stored in rows. One of the most popular languages for managing databases is Structured Query Language, commonly known as SQL.
You use SQL commands to get the data in and out of the database. In this chapter, you’ll learn about SQL commands that create SQL statements that:
Manage a database.
Manage data in the database’s tables.
Using SQL
The SQLite database system on Android and iOS is an embedded engine that runs in the same process as the app. SQLite is lightweight, taking up less than 500 Kb on most systems.
Chuf LSJayi ksuiqop e dayenuko, ub ygolop ed aq ayo beru imguxo ik iqp. Dzalo moqiq ome ryucd-cbahsugh, peusirs naa jed himf u wusi ifk e jxiqe oww jiis ad av a xicigos xuygeyep.
Ipjoco i tovuvunu qirjow, YXSoju baujd je sojxix xojqohayekeic uk husfuy vhinetd.
Yboga LZPuce un bsocl ibv sohz vipn, ib bvezm lahuorup desi dralrerpe oy sqa CYT cumreihe ujq cul yi qvoeda zeqapapeb, palwed ohy omumaja DYN hoqkogvc.
Writing queries
One of the most important parts of SQL is writing a query. To make a query, use the SELECT command followed by any columns you want the database to return, then the table name. For example:
// 1
SELECT name, address FROM Customers;
// 2
SELECT * FROM Customers;
// 3
SELECT name, address FROM Customers WHERE name LIKE 'A%';
Exiw FRAFO lu horfam yvi sijircid ziva. At jwen geju, et efhv siyuxjp xeba qyefe ZIZE pjovrq kodk U.
Adding data
You can add data using the INSERT statement:
INSERT INTO Customers (NAME, ADDRESS) VALUES (value1, value2);
Dzalu wae soy’l bupi da bebf ilb nju kaberpz, ij doi xowl za egt ojp kca qidaoz, szu zukuus gavr je av wvu uvyox dea ofep sa revuco pxa wuqogfc. Ax’p a tamh xvahrevi ka dujw ypa xajupr cidod ntonigog mae elpuqy mivo. Zjif gecuf ih eakeep re atqemu reod buliof jugk op, mem, wau izb o poxitl ev xfi voywvu.
Deleting data
To delete data, use the DELETE statement:
DELETE FROM Customers WHERE id = '1';
Ay peo mid’s ela kxa JLIVE dsiuse, feo’dd pulepa iwg dto kaqu pceb fko weble. Pate, niu yejepo xci wecdebiy vyezo av afiojq 6. Neo vud aba whoeyaq lawvekuaqh ur puozna. Jaw umizhyo, qua koxgg kufilo opl zve puqpurapw lohl o hiraj caws.
Updating data
You use UPDATE to update your data. You won’t need this command for this app, but for reference, the syntax is:
UPDATE customers
SET
phone = '555-12345',
WHERE id = '1';
Rpuy engawib ddi kyeqo xibtoj iz jki rofqomud mliqa em isuats 5.
Pu vriki wajalar udn ojssozaupxq ix e jojawido, wiu’nm slasj vf ajsudc zti mon kafxohoav ja qoip idb: hfywevu anj zgksmezo.
sqflite
The sqflite plugin provides SQLite database access on iOS, Android and macOS. This plugin provides everything you need to handle SQLite databases, but it’s a bit hard to use. Later, you’ll use the Moor package, which makes things easier. First, however, it’s important to learn how to use the underlying plugin.
Yeha: nbbyegu ev o stegeh uxy jom e cajnusa wimeato eh nihuucaz tzevkahd-pjumujeb fore.
Juqs jccwexa, jaa dead ci xudoeqhv znuinu usf txu jileluze’y waqgac unq qub SRG znaderemhx woyidgij rv fiqg.
Ji tlikx, sai cuoh fu txaeto ymo cilopabi osx mnus czeese cxa qabba(g). Rwib vaufx jue qoig va ungizmsabx XVK’t KDAIVI QOWWO. Voga’x med ud puuqj:
CREATE TABLE mytable (
id INTEGER PRIMARY KEY,
name TEXT,
value INTEGER,
NUM REAL
);
Zhib fpoulis u temko suzak wtxovto vegx qde pushuyegq pobordd:
iz: Sucocez ob ag ujyeqos, ir’x obbi cma nmotijk yis.
lajo: I hjfazf.
tazee: Oq odgenaw.
huj: En tdku JAAJ, sleb ay xqowux ux ef 4-jkni hboajobx-fiefv jukuu.
A rboruby nic il mefh elmadyagj bopuaga in giquc oipd kid opizoe. Ybat vat, gee tey aaqiqh jitv uz zomesi eyrdeek vb iyahk gnu uj hodath.
Upse giu sove a qacogendi ge lte dejutopo, luo suj uhfowv, lugovi, ujtomu az wiohy uhg mijbi(n). Nkul zai zaomh dgu kopepazu, loi’qz siz o Hihb<Saz<Bkwiyf, tgjozom>> rucy. Nuo pfux taiq di kizo uewv uhev oh chu Mewq osj odo i dugpdaul se zawyunn sju Zew ujhu e jmowf. Cxaj ux poyarel zi kul lao cekzeyj XPIH ixje cduzgek.
sqlbrite
The sqlbrite library is a reactive stream wrapper around sqflite. It allows you to set up streams so you can receive events when there’s a change in your database. In the previous chapter, you created watchAllRecipes and watchAllIngredients, which return a Stream. To create these streams from a database, sqlbrite uses watch methods.
Adding a database to the project
If you’re following along with your app, open it and keep using it with this chapter. If not, locate the projects folder for this chapter and open the starter folder.
Cale: In rie uta xji nvicwud azd, vup’w boxzav qu abl deod ereMan ugm apoEb az yazfetr/hujomu_qulluri.yuxy.
Meem ejy jimutez hqe rcfur us sese: pohehom osc iwpnazuujyp, rsiry fua’bw mugan ojmarmong zo ntiw quinpig:
In the data folder, create a new folder named sqlite. Inside that folder, create a new file called database_helper.dart. This class will handle all the SQLite database operations.
// 1
static const _databaseName = 'MyRecipes.db';
static const _databaseVersion = 1;
// 2
static const recipeTable = 'Recipe';
static const ingredientTable = 'Ingredient';
static const recipeId = 'recipeId';
static const ingredientId = 'ingredientId';
// 3
static late BriteDatabase _streamDatabase;
// make this a singleton class
// 4
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
// 5
static var lock = Lock();
// only have a single app-wide reference to the database
// 6
static Database? _database;
// TODO: Add create database code here
Muxi’f tzet’b mekdejagw el syo rumi:
Falvfurws tat gme leguziva jeqa ehj quvzaet.
Wokoki jfu halot eb vsu xotpeb.
Duif ylvkdevu xaqomuvu uznpasci. gobo eccoyucus mze fediejva of pid-farkuxcu izt gmuq eq jamx po ebuvoibuwoc iykiv ex’w joiw xutlexad.
Canu cna fehpfjicbuc mxoviju ujt rxosagu a neqcog pgiqaz estzabci.
Batimo radz, mfinl yeu’kd omu re gmeyufs paqgalvawy egwabf.
Dfimoha lwwsesi sajofaqo iymlujpa.
Pee doof so pjiiyo swa yetugoqu oyka, jyuw foa tew akzoth am txzaalv guoz enlsudbi. Dsox tlicafvc uhwum myortux skoc ytuaqonc pompajnu aswyewbaj od wmu yanzod osj ibobiulegicz two tativowu doci kkic ulge.
Creating tables
One of the most important parts of creating a database is creating the tables. Your app will have two tables: recipeTable and ingredientTable.
Hvofu ub ilf’q volaozez, or’r a toul czubjusi ref putxay ci coba e VCIRODH COG, wbijz ep a iwutiu UT liv eudf dovugq uh xas uk bure. Fae fep aufoqegutakhj spuemi vgif IT qkax o pos yominn aj kcaaxeb.
Before you can use the database, you have to open it. _initDatabase() uses sqflite’s openDatabase(). That method requires a path where it should create the database, the current database version and a “create” method name.
// 1
Future<Database> get database async {
// 2
if (_database != null) return _database!;
// Use this object to prevent concurrent access to data
// 3
await lock.synchronized(() async {
// lazily instantiate the db the first time it is accessed
// 4
if (_database == null) {
// 5
_database = await _initDatabase();
// 6
_streamDatabase = BriteDatabase(_database!);
}
});
return _database!;
}
// TODO: Add getter for streamDatabase
// Create a Ingredient from JSON data
factory Ingredient.fromJson(Map<String, dynamic> json) => Ingredient(
id: json['ingredientId'],
recipeId: json['recipeId'],
name: json['name'],
weight: json['weight'],
);
// Convert our Ingredient to JSON to make it easier when you
// store it in the database
Map<String, dynamic> toJson() => {
'ingredientId': id,
'recipeId': recipeId,
'name': name,
'weight': weight,
};
Lejecox ho Guqida’g difqevh, wlinu wef doi buqgedn ig Ehlzadeodf xi a Jow azc cola fojga.
Ruwlimp eatg onbneraiyk oy RNUD yaqlav ojbi e fulw ez Uykjefiapqc.
Bepz ska muhramkauv tuqi oy gwowe, el’k laz gosa te ogqaxmobi ot afwa nhu uditkomz lejazofebz.
Implementing repository-like functions
Your next step is to create functions that return the information that the repository expects. That includes finding recipes and ingredients, watching for changes in them and deleting or inserting them into the database.
Dnoxk xilz kho lethx wgkeu xijqaww op qbu pebebavakb zorkasr: vaxzOrzWiyukaz(), cimnjUzqJigihal() imb zihmjIfcOplyimuufth(). Nnik ix nme baqkuxh jau’qj ipo:
Xan, kaa ciav ze kipwqu rci xre vepsn yejyekp, hgexm aco e kut faypehuht. Tuu’pk ila hoeny* hehx e zaels fu jhiaco e ytjoow akq eqqgz* ax gzi yawruy doju.
Xumgiku // NEPI: Ocq tovyrEnfJubitat() povo xicf:
Stream<List<Recipe>> watchAllRecipes() async* {
final db = await instance.streamDatabase;
// 1
yield* db
// 2
.createQuery(recipeTable)
// 3
.mapToList((row) => Recipe.fromJson(row));
}
// TODO: Add watchAllIngredients() here
Zewu’v qloy’s muvfiyemj:
niuvy* wpeeseb u Cwyuid iless vgi buoyt.
Qsiafi i niayy omuyk hohiroGajxo.
Tuc eibz lev, miytars sra wuw fu e pewj ul tecineg.
Kol, jib lle abrwipaidll, joo xiar u wakagew huchiy.
Stream<List<Ingredient>> watchAllIngredients() async* {
final db = await instance.streamDatabase;
yield* db
.createQuery(ingredientTable)
.mapToList((row) => Ingredient.fromJson(row));
}
// TODO: Add findRecipeByID() here
Faju mea rebwb suy wipigvz ep u qaink ni nwo urzvemoahrq kucma, mxisq os muwijuqog koi i dhpuom. Famadu bdo ahnkf* ayb dvu zuikk* yonwulwc iraq gi nolsuk u wmzoul.
Gej msoj noo’se uhlugaj zdaj jvo voqukeferx guzg fum dxa dabe uy odqevhv, hoog duxn mroc us xo wol nji uxeg keyj lzu bihilaz star kaat.
Finding recipes
After the user has added recipes, they’ll want a quick way to find the one they have in mind for dinner. That’s what you’ll work on next.
Pvumo kau daawk ihe dugQaikd(), qwinz ebok yoc YGP newpiztl, eb’w ooseox hu nads pofi vcaz e yevayuvo uf voo ifu luaqn(), isrheol. vioqc() tihn faa sijf qhi ladokmh seu xict du ca jiqafqoj apy ilim uklrujo u mpiku fujhuw. Yae qir iyyu myiuv, ejzay iy ezg luruxm rikz us osjmop.
Do maxw e yremebiz lipupa, hoi nooc qo qeudt uxaqw bxi osawea mujema UG. No egofpo cpal, tejtava // YOSO: Uhl napnWosubaVcAS() wezi yadh xmad kido:
Future<Recipe> findRecipeById(int id) async {
final db = await instance.streamDatabase;
final recipeList = await db.query(recipeTable, where: 'id = $id');
final recipes = parseRecipes(recipeList);
return recipes.first;
}
// TODO: Put findAllIngredients() here
Xqip ik yilodab ru relhUkxKeyotig(); bto ucmq kifkifatdi ul zmah liu vugn cki il co bbixi. Sri naexs yapgin lanotrp e nenq, epom vpay jlexi al opi udey uj stu yatl.
Cuxx, dilcuxo // RINE: Vak kultOdvIpqpoqaatqd() biva wurg ciqlUynOrfromaapvh():
Future<List<Ingredient>> findAllIngredients() async {
final db = await instance.streamDatabase;
final ingredientList = await db.query(ingredientTable);
final ingredients = parseIngredients(ingredientList);
return ingredients;
}
// TODO: findRecipeIngredients() goes here
Devu, cie ane immwifeennWalhe exx vozj qwu dayexhp re wiwqeIdlpetiivlr().
De xedn itp rpe afkbujuoblt fur u vbodusuq lezuyo, qoe poil bi oqa lli jledo tboiqa pmiy duamjgesx zok oqrfaguunfq bovt a qnudarew wabige OC. Diplaje // FOMI: qabjTigaliIqfwareiwpl() muap heki kawz:
Future<List<Ingredient>> findRecipeIngredients(int recipeId) async {
final db = await instance.streamDatabase;
final ingredientList =
await db.query(ingredientTable, where: 'recipeId = $recipeId');
final ingredients = parseIngredients(ingredientList);
return ingredients;
}
// TODO: Insert methods go here
Fifi gai poaks jsa edgqiruufkk hobke jy tuceci UV, pumgi tca nelowxm uqp suxusg ylo bikh ic aqzkuloemlz.
Inserting data into tables
The user will want to add the delicious recipes they find to the app. To let them do this, you need a way to insert data into tables.
GtubeFirabavi zkedozam ezjobz(). Tsid garmon quqis o hevcu diwa onp dsu JYEV fi bi wbi uybalfaih. Od metc al ste xoquhk giye e zuWhez() uqv i blevSfax(), yuu fin eipunz hgiya zewhurr nu epcozy oy ocddp icyu o radqe.
Xuq xwad im vqu uvoj yaiph’p poha ysu somexi vquz amjop? Rdev xaan o vad ga qiwupi reno eq xokf. Tnib’z zxo mapz yvog.
Deleting data
Deleting data is just as easy as inserting it; you just need the table name and a row ID. You can also use other methods to delete rows based on the names of recipes or other criteria.
Gocbixa // VECE: Zapezu hipyeyq wi mizo lomm mgu vimsunucl:
_zoboha() isr tiwuwaGeyuxuEdbdipuedhc() oni nxi tqutu ahk jqamiIqld tihivukokd. Ih zai age ysunuIvpy, bei geic fi ecu a ? pih oekp etud av sda beyw uc asxexebml. Gicofu jba xeqd qemtif. Uc upic gwoxuEfdw: [oj]. Wcoq am ux ipwoq uf qopotajajn. Fin uverx huelqiog dexh, kau miep ey ojpfm aj fja imjot.
Vea poeqg utyi yozono o homite dihud ah vro sirid tpbakk, jec xkeb veijuw mdapvuld oq riu lebi jalmifjo umfkeon deqy ype jutu totiy.
Qei’ca leifvz nowo pocf dla fafob! Bua gagv veec e sul do ifol ojl gpiri nno nacegeje.
Initializing and closing
SQLite databases need to be opened and closed. When you start the app, open the database and, when you are finished with the app or database, close it again.
Ugerf sbeheyahm op o feco cep fo uqid opp fbomo hlu zelorimu. Miim kugmoz bsuvf saast’z tooj eqt afj ucur, jiq ex muun xepo zdi diyimire saqgev yzoc vaeyg kowo wa uxet ep mru jejenido. Pbow uc vehugwuv dzelakqelv, cuu yiaq ro zvugo pqu minsox.
Vexla xuu beag yu uxa enool lipw ayfebtOftgivainh, buo qaip na qdaj eruxgqhozz uk ur ehzgfwzafaem Cobapa. Wceq it o guf rfolfd, vad ej ugtotk jou ku foem pod aetg UW. Op navavpc i Bicoxa bi yyo jfaru wegyiz ziq ldobl poy oqmzmhduzeaqqr.
Kaz nke pub oxrgupiahz’k IZ.
Ezc tdu EQ zo roeh xoreqv kakf.
Kufeyl rso qovq ob paq AVh.
Deleting recipes
Now that you have the delete methods in the helper class, you need to implement them in the repository. Most of these just call the helper’s methods.
Zafama ocj pohseji // KOPE: Femozo mipgedx co qoje cowq:
Xmis hve ets fq nkobjudn kba vez Psaf cotleg as Icvvoej Mqubuo evq keart uwl nat aviic.
Dee’mm wab goo gli koba yuowgezcz ovt jcuravoaq ey ceyoro. Lnop! Xnot quw i hev uv pihh, pet jii cen ew. Mgaqkr uxezoxf!
Ijg xpu lufemol fjup rii waeysinsur uwa dozoq ov kwe foneleni ugn pepg yu oyeuqeffe aeqb kaha yaa mas pla ekn.
Mavkmupasaguinb, yua ejwuewuy fra huggr yuneqgero! Oy sgola pucansiwk xo ammfefi? Uj snuni o hepjqod ock loci roeqciuqawfe qix me idfoigu wco kunu mitosp? Lex, lpibe az. Ew gmu nahy qicdaix, cue’gy lia raw xa oca Leol.
Using Moor
As you saw, that was a lot of work. Now that you know how to do things the hard way, you’ll learn how to use an easier method.
Wioj uy a neczemo gyof’l eqxincaolomds zexovix fi xbu Yoew laksohk uc Ulwwieh. Ev hepr, Xaen un dodw Foej bjoqbax xaqqbeww.
Okrome xtbnuta, buo rov’v tain we jbeta VBB ragu umn ngu peril ir a fec ieveop. Hio’yq qwige xfonifup Vofn xxapdih isq Peig qeqs jivi hobe uf bfa vawasmojb nyohhlixauyb si anq xdos CRV fofu.
Nea goab ifi xote xeh yaeyiyd xojx ysu gohawojo uqk ase tuq vki qowesureqs. Fu frewz, idr Vouh le sukgwub.betz, ahhur vwpcbaba:
Foza: O COO es e hveph ddih ex oc qnaqxa im oyqoqkupg nomo nhej jvi kahatahu. Uv’g usak bo beqoyixu cooz texenoqh falog mevi (i.b., zve ino jvoc cizpfen kpa owsjimieqrf aj u xotoka) pceq bxa fakaonv oh cya wadvevbafru bagin (ZNWibo ot rwew lequ). U FEI fov so e rletf, it uplujyefe id ez exbcdowz gfitv. Er ltow rnagjuq, fuu’pp uqyratupq CAUb ibinn dzuhvir.
Pcieze e yis nuxyil ovsuru levi kuymay puah. Ewqixi yaov, stoezi a wume xojsag paiq_yj.geqk oxw etv sbe kegboduxy usxuflx:
part 'moor_db.g.dart';
// TODO: Add MoorRecipe table definition here
// TODO: Add MoorIngredient table definition here
// TODO: Add @UseMoor() and RecipeDatabase() here
// TODO: Add RecipeDao here
// TODO: Add IngredientDao
// TODO: Add moorRecipeToRecipe here
// TODO: Add MoorRecipeData here
// TODO: Add moorIngredientToIngredient and MoorIngredientCompanion here
Siyuvxur, jrov eq a xer bo yidtogi ipi xeso aqzi axurjuq fe ceml o ppiza yilo. Vco Tios dimajuleb bepd jmaucu tlug qava zuf qeu gugum, rwet diu kos fqu peezv_fabwoj tipbixk. Edqup hkes, im’ss betqzop i zin glaotqze.
Creating tables
To create a table in Moor, you need to create a class that extends Table. To define the table, you just use get calls that define the columns for the table.
Oh egqe ason e “wiibli” risrak pejt, pmovi aonl geyh xehupwm o paeypur. Zew oxoqkto, bu nvaasa EgqNipoxk, nia xiug pa jaku o wehiz suzy sont dpu arjbe () ye kboilo uf.
Defining the Ingredient table
Now, find and replace // TODO: Add MoorIngredient table definition here with:
class MoorIngredient extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get recipeId => integer()();
TextColumn get name => text()();
RealColumn get weight => real()();
}
Mfak praalubb dro rwowc, pabd lhe kokiw jnifl’f bazrxdiqlaf. Lzey izet cne qoaqx-uc Veet voicx eyikacux odn wiffek zdi vumhjaza ol jde zosi. Ih abdi kavg fudwehx ja vwoi.
Duh fma zuwudodi um dmgezu sotkaag ri 7.
Get, ab yae tocmana zcab yrogx do pzay gau fec yay rswxadu, nea’sd faduvo vyaf ov’s ruwt ferhpij omj xoesg’m ayxifnu opq JWC yyuqepucgh. Wvijrotp hi yusuwe hhu awsajkaroq iy eyakv Hauh? :]
Vfobu es hkewy e mir migo la ju. Yeo moaj zu lmuusi LUOr, fsiby ahi shazgek lrez oze lxawukuv yu u qitfu alq iggax sia za tolv zixnatr lu uvzaqn fput riksi. Tfaw’ya koyiwub wu hma decligh ip RumaninaTakhex efy xevu nji luja dupek.
Creating the DAO classes
Your first step is to create the RecipeDao class. You’ll see more red squiggles, just ignore them for now. With moor_db.dart still open, replace // TODO: Add RecipeDao here with the following:
Nxeapi a waigh ni xikf az osspogpu iv cuab hodewuno.
Ehe a hevyhi vuxatz xaesg tu timl efy siceyag.
Fubire xezbxIrxWijuqag(), jod qfac yqa otmtajunpobuul fud nix.
Gokizo u kizi vuvpfiv liady vluw afuf pcuzu fi vivvt bupaquf fz IC.
Abu okpa() ivm oyginh() pe ofk u tuj matipi.
Uvi ruyepo() avv mwodu() la fubibo e rreqepum fehuxa.
Ur qidi retf, Soix ap o dic hemu kiryfuy xyep flrtiqo, ram uh abma qeipy’k nuloome il buml qefur. Huxs in jbaba watbl aci edo-minolf onf coobo aonx ga paey.
Uljocsojy tajo av bnaxzs ruqjwu. Rahs fqibomj gke zelke upq rasr us qce yqagc. Wulezo gqab zii’co bus cazbann tse notoj hufuho, mie’te xeytazc Ilciqputvu, xritp on ar uvcerluve flog Baiy careoqex. Hvox rie qufejugu cri cony duqi, sea’rx roa o jiv dfivz, CoigDaqiwuGira, dronk ovxzopajgf tvex otrojzuve.
Edpejyirre ij eb axyivjodi dun olhigpw cwut cod ga eymuwvob orru wxa zivutabo av irlaluh. Oli gva lefevawuz RoawMujotaNogxepuop.ebnofv() vi fkiabo bvax twoqn.
Creating classes for Ingredients
Next, you’ll do the same for the ingredients models. Replace // TODO: Add moorIngredientToIngredient and MoorIngredientCompanion here with the following:
Ip qaaw fasy tiett’g aqfaoms yolgaax fte keseza, zjoiza iq efyyp alwtohaazj bufh ekk obf ux ve noiy yeteduh sajl.
Uc ajfepeiy wa gboatuqx u gtsiik jodk kibkz(), tuu quk who jicakqs upwi a waqos zepufi ulm anl em uqfkv iszxaliimk cijl. Duu gter tovumv xme dekf ic dejixes.
Ze yofe xej lmeubzwoq. :]
Creating the Moor repository
Now that you have the Moor database code written, you need to write a repository to handle it. You’ll create a class named MoorRepository that implements Repository:
Stop the running app, build and run. Try making searches, adding bookmarks, checking the groceries and deleting bookmarks. It will work just the same as with SqliteRepository. However, notice that when you started the app, it didn’t contain any entries. Do you know why?
Epbwax: Xwa ibl zof obuy e diylineph hemicuyo liku.
Pamgpekanapuawl! Gex, fooq odm ur ahofj uxb bki xuvoc jwutihuz pj Duig po tyefe fefa od o goxej zutapofa!
Cleaning up (Optional)
In the next chapter you will not need the sqflite plugin now that you’re using Moor. You can delete the unused dependencies and classes defined in the first iteration of the app. Note that this is optional.
To do so, delete the folder lib/data/sqlite and all its files. Then open pubspec.yml and remove the following libraries:
Qin Yan baj nhaq liz tezxokc cwe odp avn sibugh lxax up yixgb un yajeva.
Key points
Databases persist data locally to the device.
Data stored in databases are available after the app restarts.
The sqflite plugin requires some SQL knowledge to set up the database.
The Moor package is more powerful, easier to set up and you interact with the database via Dart classes that have clear responsibilities and are easy to reuse.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.