본문 바로가기

Flutter

Creating a database using classes in Flutter/Dart

반응형

When developing an app, there are times when a database is needed.

 

Let's imagine creating an app that handles the following types of data.

Product ID Product Name Product Colors Product Price
401 ABC Red, Green $1,000
202 DEF Blue, Black $2,000
105 GHK Green, Indigo $1,400
231 JKL Black $1,100

 

We have 4 columns and 5 rows, with a header row containing item names.

I'd like to transfer the table into Dart code.

 

Data Class

Simply, we can change it to a dart class as follows:

class Product {
  int id;
  String name;
  List<String> colors;
  double price;

  Product(this.id, this.name, this.colors, this.price);

  // Adding toString for debugging
  @override
  String toString() => '[$id, $name, $colors, \$$price]';
}

 

Then, we can make a List of Product objects to represent the first table contents.

void main() {
  var product1 = Product(401, 'ABC', ['Red', 'Green'], 1000);
  var product2 = Product(202, 'DEF', ['Blue', 'Black'], 2000);
  var product3 = Product(105, 'GHK', ['Green', 'Indigo'], 1400);
  var product4 = Product(231, 'JKL', ['Black'], 1100);
  
  var productList = [product1, product2, product3, product4];
  print(productList.toString());
}

class Product {
  int id;
  String name;
  List<String> colors;
  double price;

  Product(this.id, this.name, this.colors, this.price);

  // Adding toString for debugging
  @override
  String toString() => '[$id, $name, $colors, \$$price]';
}

 

JSON import / export

Without a doubt, we need import / export capabilities.

Since it is impossible to generate all the data every time we launch the app, the app has to retrieve the data from an external source.

 

The Dart language provides a library for jsonEncode and jsonDecode.

In the following diagram, ② is provided by dart:convert library.

【 Class ↔ JSON <Map> ↔ JSON <String> 】

 

For ① in the above, we're supposed to add some code to class.

We're supposed to convert the class variables into a Map<String, dynamic> object.

 

First, let's create a method to export variables as a JSON Map.

  // Converts a Product object into a JSON Map
  Map<String, dynamic> toJson() => {'id': id, 'name': name, 'colors': colors, 'price': price};

 

Second, we need a method to create an object instance from a JSON Map.

  // Converts a JSON Map into a Product object
  factory Product.fromJson(Map<String, dynamic> json) {
    return Product(json['id'], json['name'], json['colors'].cast<String>(), json['price']);
  }

 

Here, I used cast<String>() to convert the dynamic type to a String type.

If we don't use cast here, we'll encounter the following error:

type 'List<dynamic>' is not a subtype of type 'List<String>'

 

 

Now, we're ready to use JSON import and export. I'm adding a sample code snippet to implement ① and ②.

import 'dart:convert';

void main() {
  var product1 = Product(401, 'ABC', ['Red', 'Green'], 1000);

  // Convert the Product object into a JSON Map
  var jsonMap = product1.toJson();
  print(jsonMap);

  // Convert the JSON Map into a JSON String
  var jsonString = jsonEncode(jsonMap);
  print(jsonString);

  // Convert the JSON String back into a JSON Map
  var jsonMapFromString = jsonDecode(jsonString);
  print(jsonMapFromString);

  // Create a new Product object from the JSON Map
  var product2 = Product.fromJson(jsonMapFromString);
  print(product2);
}

class Product {
  int id;
  String name;
  List<String> colors;
  double price;

  Product(this.id, this.name, this.colors, this.price);

  // Converts a Product object into a JSON Map
  Map<String, dynamic> toJson() =>
      {'id': id, 'name': name, 'colors': colors, 'price': price};

  // Converts a JSON Map into a Product object
  factory Product.fromJson(Map<String, dynamic> json) {
    return Product(json['id'], json['name'], json['colors'].cast<String>(), json['price']);
  }

  // Adding toString for debugging
  @override
  String toString() => '[$id, $name, $colors, \$$price]';
}

 

Result:

{id: 401, name: ABC, colors: [Red, Green], price: 1000.0}
{"id":401,"name":"ABC","colors":["Red","Green"],"price":1000.0}
{id: 401, name: ABC, colors: [Red, Green], price: 1000.0}
[401, ABC, [Red, Green], $1000.0]

 

Comparable

In many cases, data class instances are managed as a List, and there arises a need to sort the created List.

The Product class needs to implement a Comparable interface to use the sort method.

class Product implements Comparable<Product> {
  /**
   * Previous codes
   */

  @override
  int compareTo(other) {
    return id.compareTo(other.id);
  }
}

 

We can sort the List<Product> by adding above codes.

void main() {
  var product1 = Product(401, 'ABC', ['Red', 'Green'], 1000);
  var product2 = Product(202, 'DEF', ['Blue', 'Black'], 2000);
  var product3 = Product(105, 'GHK', ['Green', 'Indigo'], 1400);
  var product4 = Product(231, 'JKL', ['Black'], 1100);

  var productList = [product1, product2, product3, product4];

  productList.sort();
  showProductList(productList);
}

class Product implements Comparable<Product> {
  int id;
  String name;
  List<String> colors;
  double price;

  Product(this.id, this.name, this.colors, this.price);

  // Converts a Product object into a JSON Map
  Map<String, dynamic> toJson() =>
      {'id': id, 'name': name, 'colors': colors, 'price': price};

  // Converts a JSON Map into a Product object
  factory Product.fromJson(Map<String, dynamic> json) {
    return Product(
        json['id'], json['name'], json['colors'].cast<String>(), json['price']);
  }

  // Adding toString for debugging
  @override
  String toString() => '[$id, $name, $colors, \$$price]';

  @override
  int compareTo(other) {
    return id.compareTo(other.id);
  }
}

 

Equatable

Sometimes, we need to determine whether two class instances are equal under certain conditions.

In our Product class, let's assume we determine the equality of two instances based on the name variable.

We're going to extend Equatable class to enable equality check.

 

First of all, we need to add Equatable library to our project.

flutter pub add equatable

 

Now, Let Product class extends Equatable.

import 'package:equatable/equatable.dart';

class Product extends Equatable implements Comparable<Product> {
  /**
   * Previous codes
   */

  @override
  List<Object?> get props => [name];
}

 

Let's test the equality of two instances that have the same name.

import 'package:equatable/equatable.dart';

void main() {
  var product1 = Product(401, 'ABC', ['Red', 'Green'], 1000);
  var product2 = Product(202, 'ABC', ['Blue', 'Black'], 2000);

  if (product1 == product2) {
    print('Product 1 is equal to Product 2');
  } else {
    print('Product 1 is not equal to Product 2');
  }
}

class Product extends Equatable implements Comparable<Product> {
  int id;
  String name;
  List<String> colors;
  double price;

  Product(this.id, this.name, this.colors, this.price);

  // Converts a Product object into a JSON Map
  Map<String, dynamic> toJson() =>
      {'id': id, 'name': name, 'colors': colors, 'price': price};

  // Converts a JSON Map into a Product object
  factory Product.fromJson(Map<String, dynamic> json) {
    return Product(
        json['id'], json['name'], json['colors'].cast<String>(), json['price']);
  }

  // Adding toString for debugging
  @override
  String toString() => '[$id, $name, $colors, \$$price]';

  @override
  int compareTo(other) {
    return id.compareTo(other.id);
  }

  @override
  List<Object?> get props => [name];
}

 

Result:

Product 1 is equal to Product 2

 

반응형