Flutter - Veritabanı Kavramları

Flutter, veritabanları ile çalışmak için birçok gelişmiş paket sağlar. En önemli paketler -

  • sqflite - SQLite veritabanına erişmek ve bunları işlemek için kullanılır ve

  • firebase_database - Google'ın bulutta barındırılan NoSQL veritabanına erişmek ve bunları işlemek için kullanılır.

Bu bölümde, her birini ayrıntılı olarak tartışalım.

SQLite

SQLite veritabanı, fiili ve standart SQL tabanlı gömülü veritabanı motorudur. Küçük ve zaman içinde test edilmiş veritabanı motorudur. sqflite paketi, SQLite veritabanı ile verimli çalışmak için birçok işlevsellik sağlar. SQLite veritabanı motorunu işlemek için standart yöntemler sağlar. Sqflite paketinin sağladığı temel işlevler aşağıdaki gibidir -

  • Bir SQLite veritabanı oluşturun / açın (openDatabase yöntemi).

  • SQLite veritabanına karşı SQL deyimini (yürütme yöntemi) yürütün.

  • Sorgulamak ve SQLite veritabanından bilgi almak için gereken koda indirgenecek gelişmiş sorgu yöntemleri (sorgu yöntemi).

Sqflite paketini kullanarak standart bir SQLite veritabanı motorundan ürün bilgilerini depolamak ve almak için bir ürün uygulaması oluşturalım ve SQLite veritabanı ve sqflite paketinin arkasındaki konsepti anlayalım.

  • Android stüdyosunda yeni bir Flutter uygulaması oluşturun, product_sqlite_app.

  • Varsayılan başlangıç ​​kodunu (main.dart) product_rest_app kodumuzla değiştirin .

  • Dan klasör varlıkları Kopya product_nav_app için product_rest_app ve * pubspec.yaml` dosya içindeki varlıkları ekleyin.

flutter: 
   assets: 
      - assets/appimages/floppy.png 
      - assets/appimages/iphone.png 
      - assets/appimages/laptop.png 
      - assets/appimages/pendrive.png 
      - assets/appimages/pixel.png 
      - assets/appimages/tablet.png
  • Pubspec.yaml dosyasında sqflite paketini aşağıda gösterildiği gibi yapılandırın -

dependencies: sqflite: any

Herhangi birinin yerine sqflite'ın en son sürüm numarasını kullanın

  • Pubspec.yaml dosyasında path_provider paketini aşağıda gösterildiği gibi yapılandırın -

dependencies: path_provider: any
  • Burada path_provider paketi, sistemin geçici klasör yolunu ve uygulamanın yolunu almak için kullanılır. Herhangi birinin yerine sqflite'ın en son sürüm numarasını kullanın .

  • Android stüdyosu, pubspec.yaml dosyasının güncellendiğini bildirir.

  • Bağımlılıkları al seçeneğini tıklayın. Android stüdyosu paketi İnternet'ten alacak ve uygulama için uygun şekilde yapılandıracaktır.

  • Veritabanında, ad, fiyat, vb. Gibi Ürün özelliklerinin yanı sıra ek alan olarak birincil anahtar, id'ye ihtiyacımız var. Bu nedenle, Product sınıfına id özelliğini ekleyin. Ayrıca, ürün nesnesini Map nesnesine dönüştürmek için toMap adlı yeni bir yöntem ekleyin. fromMap ve toMap, Product nesnesini serileştirmek ve serileştirmek için kullanılır ve veritabanı işleme yöntemlerinde kullanılır.

class Product { 
   final int id; 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   static final columns = ["id", "name", "description", "price", "image"]; 
   Product(this.id, this.name, this.description, this.price, this.image); 
   factory Product.fromMap(Map<String, dynamic> data) {
      return Product( 
         data['id'], 
         data['name'], 
         data['description'], 
         data['price'], 
         data['image'], 
      ); 
   } 
   Map<String, dynamic> toMap() => {
      "id": id, 
      "name": name, 
      "description": description, 
      "price": price, 
      "image": image 
   }; 
}
  • SQLite ile ilgili işlevselliği yazmak için lib klasöründe Database.dart adlı yeni bir dosya oluşturun .

  • Database.dart içinde gerekli import ifadesini içe aktarın.

import 'dart:async'; 
import 'dart:io'; 
import 'package:path/path.dart'; 
import 'package:path_provider/path_provider.dart'; 
import 'package:sqflite/sqflite.dart'; 
import 'Product.dart';
  • Burada aşağıdaki noktalara dikkat edin -

    • async zaman uyumsuz yöntemler yazmak için kullanılır.

    • io dosyalara ve dizinlere erişmek için kullanılır.

    • path dosya yollarıyla ilgili dart çekirdek yardımcı program işlevine erişmek için kullanılır.

    • path_provider geçici ve uygulama yolunu almak için kullanılır.

    • sqflite SQLite veritabanını işlemek için kullanılır.

  • Yeni bir sınıf oluştur SQLiteDbProvider

  • Aşağıda belirtildiği gibi tekil tabanlı, statik bir SQLiteDbProvider nesnesi bildirin -

class SQLiteDbProvider { 
   SQLiteDbProvider._(); 
   static final SQLiteDbProvider db = SQLiteDbProvider._(); 
   static Database _database; 
}
  • SQLiteDBProvoider nesnesine ve yöntemine statik db değişkeni üzerinden erişilebilir.

SQLiteDBProvoider.db.<emthod>
  • Future <Database> türündeki veritabanını (Gelecek seçeneği) almak için bir yöntem oluşturun. Veritabanının oluşturulması sırasında ürün tablosu oluşturun ve ilk verileri yükleyin.

Future<Database> get database async { 
   if (_database != null) 
   return _database; 
   _database = await initDB(); 
   return _database; 
}
initDB() async { 
   Directory documentsDirectory = await getApplicationDocumentsDirectory(); 
   String path = join(documentsDirectory.path, "ProductDB.db"); 
   return await openDatabase(
      path, 
      version: 1,
      onOpen: (db) {}, 
      onCreate: (Database db, int version) async {
         await db.execute(
            "CREATE TABLE Product ("
            "id INTEGER PRIMARY KEY,"
            "name TEXT,"
            "description TEXT,"
            "price INTEGER," 
            "image TEXT" ")"
         ); 
         await db.execute(
            "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
            values (?, ?, ?, ?, ?)", 
            [1, "iPhone", "iPhone is the stylist phone ever", 1000, "iphone.png"]
         ); 
         await db.execute(
            "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
            values (?, ?, ?, ?, ?)", 
            [2, "Pixel", "Pixel is the most feature phone ever", 800, "pixel.png"]
         ); 
         await db.execute(
            "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
            values (?, ?, ?, ?, ?)", 
            [3, "Laptop", "Laptop is most productive development tool", 2000, "laptop.png"]\
         ); 
         await db.execute( 
            "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
            values (?, ?, ?, ?, ?)", 
            [4, "Tablet", "Laptop is most productive development tool", 1500, "tablet.png"]
         );
         await db.execute( 
            "INSERT INTO Product 
            ('id', 'name', 'description', 'price', 'image') 
            values (?, ?, ?, ?, ?)", 
            [5, "Pendrive", "Pendrive is useful storage medium", 100, "pendrive.png"]
         );
         await db.execute( 
            "INSERT INTO Product 
            ('id', 'name', 'description', 'price', 'image') 
            values (?, ?, ?, ?, ?)", 
            [6, "Floppy Drive", "Floppy drive is useful rescue storage medium", 20, "floppy.png"]
         ); 
      }
   ); 
}
  • Burada aşağıdaki yöntemleri kullandık -

    • getApplicationDocumentsDirectory - Uygulama dizini yolunu döndürür

    • join- Sisteme özel yol oluşturmak için kullanılır. Bunu veritabanı yolu oluşturmak için kullandık.

    • openDatabase - Bir SQLite veritabanını açmak için kullanılır

    • onOpen - Bir veritabanını açarken kod yazmak için kullanılır

    • onCreate - Bir veritabanı ilk kez oluşturulurken kod yazmak için kullanılır

    • db.execute- SQL sorgularını yürütmek için kullanılır. Bir sorguyu kabul eder. Sorgu yer tutucusuna (?) Sahipse, değerleri ikinci bağımsız değişkende liste olarak kabul eder.

  • Veritabanındaki tüm ürünleri almak için bir yöntem yazın -

Future<List<Product>> getAllProducts() async { 
   final db = await database; 
   List<Map> 
   results = await db.query("Product", columns: Product.columns, orderBy: "id ASC"); 
   
   List<Product> products = new List(); 
   results.forEach((result) { 
      Product product = Product.fromMap(result); 
      products.add(product); 
   }); 
   return products; 
}
  • Burada aşağıdakileri yaptık -

    • Tüm ürün bilgilerini almak için sorgu yöntemi kullanıldı. sorgu, tüm sorguyu yazmadan tablo bilgilerini sorgulamak için kısayol sağlar. sorgu yöntemi, sütunlar, orderBy vb. girdilerimizi kullanarak uygun sorguyu kendisi üretecektir.

    • Tablodaki tüm satırları tutan sonuç nesnesini döngüye alarak ürün detaylarını almak için Ürünün fromMap yöntemi kullanıldı.

  • Ürüne özel almak için bir yöntem yazın id

Future<Product> getProductById(int id) async {
   final db = await database; 
   var result = await db.query("Product", where: "id = ", whereArgs: [id]); 
   return result.isNotEmpty ? Product.fromMap(result.first) : Null; 
}
  • Burada, filtreleri nereye ve nereye uyguladığımızı kullandık.

  • Üç yöntem oluşturun - ürünü veri tabanından eklemek, güncellemek ve silmek için yöntem ekleme, güncelleme ve silme.

insert(Product product) async { 
   final db = await database; 
   var maxIdResult = await db.rawQuery(
      "SELECT MAX(id)+1 as last_inserted_id FROM Product");

   var id = maxIdResult.first["last_inserted_id"]; 
   var result = await db.rawInsert(
      "INSERT Into Product (id, name, description, price, image)" 
      " VALUES (?, ?, ?, ?, ?)", 
      [id, product.name, product.description, product.price, product.image] 
   ); 
   return result; 
}
update(Product product) async { 
   final db = await database; 
   var result = await db.update("Product", product.toMap(), 
   where: "id = ?", whereArgs: [product.id]); return result; 
} 
delete(int id) async { 
   final db = await database; 
   db.delete("Product", where: "id = ?", whereArgs: [id]); 
}
  • Database.dart dosyasının son kodu aşağıdaki gibidir -

import 'dart:async'; 
import 'dart:io'; 
import 'package:path/path.dart'; 
import 'package:path_provider/path_provider.dart'; 
import 'package:sqflite/sqflite.dart'; 
import 'Product.dart'; 

class SQLiteDbProvider {
   SQLiteDbProvider._(); 
   static final SQLiteDbProvider db = SQLiteDbProvider._(); 
   static Database _database; 
   
   Future<Database> get database async {
      if (_database != null) 
      return _database; 
      _database = await initDB(); 
      return _database; 
   } 
   initDB() async {
      Directory documentsDirectory = await 
      getApplicationDocumentsDirectory(); 
      String path = join(documentsDirectory.path, "ProductDB.db"); 
      return await openDatabase(
         path, version: 1, 
         onOpen: (db) {}, 
         onCreate: (Database db, int version) async {
            await db.execute(
               "CREATE TABLE Product (" 
               "id INTEGER PRIMARY KEY," 
               "name TEXT," 
               "description TEXT," 
               "price INTEGER," 
               "image TEXT"")"
            ); 
            await db.execute(
               "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
               values (?, ?, ?, ?, ?)", 
               [1, "iPhone", "iPhone is the stylist phone ever", 1000, "iphone.png"]
            ); 
            await db.execute( 
               "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
               values (?, ?, ?, ?, ?)", 
               [2, "Pixel", "Pixel is the most feature phone ever", 800, "pixel.png"]
            );
            await db.execute(
               "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
               values (?, ?, ?, ?, ?)", 
               [3, "Laptop", "Laptop is most productive development tool", 2000, "laptop.png"]
            ); 
            await db.execute( 
               "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
               values (?, ?, ?, ?, ?)", 
               [4, "Tablet", "Laptop is most productive development tool", 1500, "tablet.png"]
            ); 
            await db.execute( 
               "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
               values (?, ?, ?, ?, ?)", 
               [5, "Pendrive", "Pendrive is useful storage medium", 100, "pendrive.png"]
            );
            await db.execute( 
               "INSERT INTO Product ('id', 'name', 'description', 'price', 'image') 
               values (?, ?, ?, ?, ?)", 
               [6, "Floppy Drive", "Floppy drive is useful rescue storage medium", 20, "floppy.png"]
            ); 
         }
      ); 
   }
   Future<List<Product>> getAllProducts() async {
      final db = await database; 
      List<Map> results = await db.query(
         "Product", columns: Product.columns, orderBy: "id ASC"
      ); 
      List<Product> products = new List();   
      results.forEach((result) {
         Product product = Product.fromMap(result); 
         products.add(product); 
      }); 
      return products; 
   } 
   Future<Product> getProductById(int id) async {
      final db = await database; 
      var result = await db.query("Product", where: "id = ", whereArgs: [id]); 
      return result.isNotEmpty ? Product.fromMap(result.first) : Null; 
   } 
   insert(Product product) async { 
      final db = await database; 
      var maxIdResult = await db.rawQuery("SELECT MAX(id)+1 as last_inserted_id FROM Product"); 
      var id = maxIdResult.first["last_inserted_id"]; 
      var result = await db.rawInsert(
         "INSERT Into Product (id, name, description, price, image)" 
         " VALUES (?, ?, ?, ?, ?)", 
         [id, product.name, product.description, product.price, product.image] 
      ); 
      return result; 
   } 
   update(Product product) async { 
      final db = await database; 
      var result = await db.update(
         "Product", product.toMap(), where: "id = ?", whereArgs: [product.id]
      ); 
      return result; 
   } 
   delete(int id) async { 
      final db = await database; 
      db.delete("Product", where: "id = ?", whereArgs: [id]);
   } 
}
  • Ürün bilgilerini almak için ana yöntemi değiştirin.

void main() {
   runApp(MyApp(products: SQLiteDbProvider.db.getAllProducts())); 
}
  • Burada, tüm ürünleri veritabanından almak için getAllProducts yöntemini kullandık.

  • Uygulamayı çalıştırın ve sonuçları görün. Ürün bilgilerinin depolanması ve yerel SQLite veritabanından getirilmesi dışında, önceki örnek olan Accessing Product service API'ye benzer olacaktır .

Cloud Firestore

Firebase, bir BaaS uygulama geliştirme platformudur. Kimlik doğrulama hizmeti, bulut depolama vb. Mobil uygulama geliştirmeyi hızlandırmak için birçok özellik sağlar, Firebase'in ana özelliklerinden biri bulut tabanlı gerçek zamanlı bir NoSQL veritabanı olan Cloud Firestore'dur.

Flutter, Cloud Firestore ile programlamak için cloud_firestore adlı özel bir paket sağlar. Cloud Firestore'da bir çevrimiçi ürün mağazası oluşturalım ve ürün mağazasına erişmek için bir uygulama oluşturalım.

  • Android stüdyosunda yeni bir Flutter uygulaması oluşturun, product_firebase_app.

  • Varsayılan başlangıç ​​kodunu (main.dart) product_rest_app kodumuzla değiştirin .

  • Product.dart dosyasını product_rest_app'den lib klasörüne kopyalayın.

class Product { 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Product(this.name, this.description, this.price, this.image); 
   factory Product.fromMap(Map<String, dynamic> json) {
      return Product( 
         json['name'], 
         json['description'], 
         json['price'], 
         json['image'], 
      ); 
   }
}
  • Varlıklar klasörünü product_rest_app'den product_firebase_app'e kopyalayın ve varlıkları pubspec.yaml dosyasına ekleyin.

flutter:
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • Pubspec.yaml dosyasında cloud_firestore paketini aşağıda gösterildiği gibi yapılandırın -

dependencies: cloud_firestore: ^0.9.13+1
  • Burada cloud_firestore paketinin en son sürümünü kullanın.

  • Android stüdyosu, pubspec.yaml dosyasının burada gösterildiği gibi güncellendiğini bildirir -

  • Bağımlılıkları al seçeneğini tıklayın. Android stüdyosu paketi İnternet'ten alacak ve uygulama için uygun şekilde yapılandıracaktır.

  • Aşağıdaki adımları kullanarak Firebase'de bir proje oluşturun -

    • Adresinde Ücretsiz planı seçerek bir Firebase hesabı oluşturun https://firebase.google.com/pricing/.

    • Firebase hesabı oluşturulduktan sonra, projeye genel bakış sayfasına yönlendirilecektir. Firebase tabanlı tüm projeleri listeler ve yeni bir proje oluşturma seçeneği sunar.

    • Proje ekle'ye tıkladığınızda bir proje oluşturma sayfası açılacaktır.

    • Proje adı olarak products app db'yi girin ve Create project seçeneğini tıklayın.

    • * Firebase konsoluna gidin.

    • Projeye genel bakış'ı tıklayın. Projeye genel bakış sayfasını açar.

    • Android simgesine tıklayın. Android geliştirmeye özel proje ayarını açacaktır.

    • Android Paket adını girin, com.tutorialspoint.flutterapp.product_firebase_app.

    • Uygulamayı Kaydet'i tıklayın. Google_service.json adlı bir proje yapılandırma dosyası oluşturur.

    • Google_service.json dosyasını indirin ve ardından projenin android / app dizinine taşıyın. Bu dosya, uygulamamız ile Firebase arasındaki bağlantıdır.

    • Android / app / build.gradle'ı açın ve aşağıdaki kodu ekleyin -

apply plugin: 'com.google.gms.google-services'
    • Android / build.gradle dosyasını açın ve aşağıdaki yapılandırmayı dahil edin -

buildscript {
   repositories { 
      // ... 
   } 
   dependencies { 
      // ... 
      classpath 'com.google.gms:google-services:3.2.1' // new 
   } 
}

    Burada eklenti ve sınıf yolu, google_service.json dosyasını okumak amacıyla kullanılır.

    • Android / app / build.gradle'ı açın ve aşağıdaki kodu da ekleyin.

android {
   defaultConfig { 
      ... 
      multiDexEnabled true 
   } 
   ...
}
dependencies {
   ... 
   compile 'com.android.support: multidex:1.0.3' 
}

    Bu bağımlılık, android uygulamasının birden çok dex işlevini kullanmasını sağlar.

    • Firebase Console'da kalan adımları izleyin veya atlayın.

  • Aşağıdaki adımları kullanarak yeni oluşturulan projede bir ürün mağazası oluşturun -

    • Firebase konsoluna gidin.

    • Yeni oluşturulan projeyi açın.

    • Soldaki menüden Veritabanı seçeneğine tıklayın.

    • Veritabanı oluştur seçeneğini tıklayın.

    • Test modunda başlat'ı ve ardından Etkinleştir'i tıklayın.

    • Koleksiyon ekle'yi tıklayın. Ürünü koleksiyon adı olarak girin ve ardından İleri'ye tıklayın.

    • Örnek ürün bilgilerini buradaki resimde gösterildiği gibi girin -

  • Belge ekle seçeneklerini kullanarak ek ürün bilgilerini ekleyin .

  • Main.dart dosyasını açın ve Cloud Firestore eklenti dosyasını içe aktarın ve http paketini kaldırın.

import 'package:cloud_firestore/cloud_firestore.dart';
  • ParseProducts'ı kaldırın ve ürünleri Ürün hizmeti API'si yerine Cloud Firestore'dan almak için fetchProducts'ı güncelleyin.

Stream<QuerySnapshot> fetchProducts() { 
   return Firestore.instance.collection('product').snapshots(); }
  • Burada Firestore.instance.collection yöntemi, bulut mağazasında bulunan ürün koleksiyonuna erişmek için kullanılır. Firestore.instance.collection, gerekli belgeleri elde etmek için koleksiyonu filtrelemek için birçok seçenek sunar. Ancak, tüm ürün bilgilerini almak için herhangi bir filtre uygulamadık.

  • Cloud Firestore, Dart Stream konsepti aracılığıyla toplama sağlar ve bu nedenle MyApp ve MyHomePage widget'ındaki ürün türünü Future <list <Product>> seçeneğinden Stream <QuerySnapshot> olarak değiştirin.

  • FutureBuilder yerine StreamBuilder kullanmak için MyHomePage küçük aracının derleme yöntemini değiştirin.

@override 
Widget build(BuildContext context) {
   return Scaffold(
      appBar: AppBar(title: Text("Product Navigation")), 
      body: Center(
         child: StreamBuilder<QuerySnapshot>(
            stream: products, builder: (context, snapshot) {
               if (snapshot.hasError) print(snapshot.error); 
               if(snapshot.hasData) {
                  List<DocumentSnapshot> 
                  documents = snapshot.data.documents; 
                  
                  List<Product> 
                  items = List<Product>(); 
                  
                  for(var i = 0; i < documents.length; i++) { 
                     DocumentSnapshot document = documents[i]; 
                     items.add(Product.fromMap(document.data)); 
                  } 
                  return ProductBoxList(items: items);
               } else { 
                  return Center(child: CircularProgressIndicator()); 
               }
            }, 
         ), 
      )
   ); 
}
  • Burada, ürün bilgilerini List <DocumentSnapshot> türü olarak getirdik. Widget'ımız ProductBoxList belgelerle uyumlu olmadığından, belgeleri List <Product> türüne dönüştürdük ve daha sonra kullandık.

  • Son olarak, uygulamayı çalıştırın ve sonucu görün. SQLite uygulamasıyla aynı ürün bilgilerini kullandığımız ve yalnızca depolama ortamını değiştirdiğimizden, ortaya çıkan uygulama SQLite uygulama uygulamasıyla aynı görünüyor .