10

I am using hive as my NoSQL local database in my flutter app.

Following is my Hive Class:

import 'dart:convert';

import 'package:hive/hive.dart';
import 'package:lpa_exam/src/model/listofexams.dart';
import 'package:lpa_exam/src/model/profile.dart';
part 'hiveprofile.g.dart';

@HiveType()
class PersonModel extends HiveObject{
  @HiveField(0)
  String language;

  @HiveField(1)
  String examName;

  @HiveField(2)
  int examId;

  @HiveField(3)
  Profile profile;

  @HiveField(4)
  ListExam listexam;

  @override
  String toString() {
    return jsonEncode({
      'language': language,
      'examName': this.examName,
      'examId': examId,
      'profile': profile,
      'listexam': listexam
    });
  }

  PersonModel(
      this.language, this.examName, this.examId, this.profile, this.listexam);
}

So, my requirement is that on every successful login I am supposed to update profile object. But for that, I have to set all of the others also.

How can I just update the profile object only?

Code:

_personBox = Hive.openBox('personBox');
          await _personBox.then((item) {
            if (!item.isEmpty) {
              print('empty');
              item.putAt(0, PersonModel(...,..,..,..,...,..));
            }
          });

I am using hive version 1.2.0.

Reference: https://resocoder.com/2019/09/30/hive-flutter-tutorial-lightweight-fast-database/

padaleiana
  • 955
  • 1
  • 14
  • 23
Gaurav Kumar
  • 1,111
  • 6
  • 25
  • 52

6 Answers6

7

Just use the putAt() method, like this:

Hive.box('products').putAt(productIndex, _product);

You can get the productIndex by using the index from the listView.Builder like this:

ListView.builder(
  itemBuilder: (cxt, i) {

    return Row(
      children:[
      Text(product[i].name),
        MaterialButton(
          child:Text('edit'),

          onPressed:(){

        Hive.box('products').putAt(i,product);
      }
    ),
  ]
),
}}
Rohan Bari
  • 7,482
  • 3
  • 14
  • 34
Hamza Bashir
  • 85
  • 1
  • 4
3

Try .save() method:

_personBox = Hive.openBox('personBox');
      await _personBox.then((item) {
        if (!item.isEmpty) {
          print('empty');
          var i = item.getAt(0, PersonModel(...,..,..,..,...,..));
          i.profile = Somevalue;
          i.save();
        }
 });
Gagan Raghunath
  • 1,673
  • 1
  • 8
  • 5
  • hi, I have tried this but hive's .getAt method takes only one parameter, how you have passed model to it? it is not working can you please help me to update a single value in the record. thanks – Sandeep Apr 20 '20 at 11:11
  • @Sandeep You have to give a type to your box, like `Box _box;` – happy-san Feb 02 '21 at 10:06
  • @happy_san thanks for the answer, but the issue was resolved almost 1 year ago... – Sandeep Feb 11 '21 at 06:59
0

So i was having a hard time with the exact same problem and what i found was you can essentially enter null values or reference a previous value/ an already existing value. Here is an example where you have to enter the profile object but you already have the other attributes saved in the database.

var language = Hive.box('personBox').getAt(0).language;
var examName = Hive.box('personBox').getAt(0).examName;
var examID = Hive.box('personBox').getAt(0).examID;
//Add the details you want to add here
var profile = SomeValue;
var listExam = Hive.box('personBox').getAt(0).listExam;

//Adding the details
Hive.box('personBox').putAt(0, PersonModel(language, examName, examID, profile, listExam));

Now the problem is that if there are no instances in your database of the objects you will get an out of range error. So to mitigate that your also going to need to put this extra line of code in your main().

if (Hive.box('personBox').isEmpty == true) {
//add dummy values here for first initialization
Hive.box('personBox').add(PersonModel('', '', 0, '', ''));
}

Keep in mind you will have to enter the other values at some point in the program, but if you just want to enter a specific value at some point in the program, you can use this. This was more of a brute force method as i couldn't find any help on how to enter a value in a specific field so i had to improvise.

Dharman
  • 30,962
  • 25
  • 85
  • 135
0

short answer: you can't

however you can create a separate box for Profile and declare an Id for PersonModel i.e. personId and use it as profile box's index.

import 'package:hive/hive.dart';
import 'package:lpa_exam/src/model/listofexams.dart';
import 'package:lpa_exam/src/model/profile.dart';
part 'hiveprofile.g.dart';

@HiveType()
class PersonModel extends HiveObject{
  @HiveField(0)
  String language;

  @HiveField(1)
  String examName;

  @HiveField(2)
  int examId;

  @HiveField(3)
  int personId;

  Profile profile; // notice profile is not a hive field anymore

  @HiveField(4)
  ListExam listexam;

  @override
  String toString() {
    return jsonEncode({
      'personId': personId,
      'language': language,
      'examName': this.examName,
      'examId': examId,
      'profile': profile,
      'listexam': listexam
    });
  }

  PersonModel(this.personId, 
      this.language, this.examName, this.examId, this.profile, this.listexam);
}

since you're using await there's no need to use .then(...)

PersonModel person = PersonModel(...,..,..,..,...,..);
Profile profile = person.profile;
Box<Profile> _profileBox = await Hive.openBox<Profile>('profileBox');
_profileBox.putAt(person.personId, profile);
Hassan Kanso
  • 237
  • 1
  • 10
0

I am not experienced with Flutter or Hive but come from an SQL background. The only way I understand if you want to update a field within row/object/record/... is to read the current record eg box.getAt(index) then assign values to all the fields, then save using box.putAt(index). I would have liked to have something like box.updateAt(index, field1 value, field2 value2). I guess there is a technical reason why this doesn't exist and it is possibly to do with performance.

I use something like below:

var videoInfoData = _videoInfoBox.getAt(index);
      var updateVideoInfo = VideoInfo(
        title: videoInfoData.title,
        author: videoInfoData.author,
        time: videoInfoData.time,
        videoURL: videoInfoData.videoURL,
        dateLoaded: videoInfoData.dateLoaded,
        dateLastPlayed: DateTime.now(),
        numberTimesPlayed: videoInfoData.numberTimesPlayed + 1,
      );
      _videoInfoBox.putAt(index, updateVideoInfo);

I would love to use:

var videoInfoData = _videoInfoBox.getAt(index);
      var updateVideoInfo = VideoInfo(  
        dateLastPlayed: DateTime.now(),
        numberTimesPlayed: videoInfoData.numberTimesPlayed + 1,
      );
      _videoInfoBox.updateAt(index, fields being updated);
Sctajc
  • 947
  • 1
  • 8
  • 18
0

In my app and tutorial I used freezed package where I have .copyWith() method to modify just specific fields of the object and then put a modified version into the Hive, either though put(dynamic key, E value) or putAt(int index, E value) method, like so:

final updatedBook = book.copyWith(readAlready: readAlready);
_books[idx] = updatedBook;
await _saveBookUseCase(updatedBook);
emit(BooksListPageState.success(List.of(_books)));

and then inside AppDatabase:

Future<void> saveBook(Book book) async {
  await _booksBox.put(
    book.id,
    BookDb(
      book.id,
      book.title,
      book.author,
      book.publicationDate,
      book.about,
      book.readAlready,
    ));
}
lomza
  • 9,412
  • 15
  • 70
  • 85
  • but what if I storing in list?? https://stackoverflow.com/questions/75906027/how-to-get-key-in-hive-from-list – Hoo Apr 01 '23 at 11:57