Reputation: 1231
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/
Upvotes: 16
Views: 31296
Reputation: 9716
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,
));
}
Upvotes: 0
Reputation: 1055
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);
Upvotes: 0
Reputation: 305
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);
Upvotes: 0
Reputation: 1
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.
Upvotes: 0
Reputation: 135
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);
}
),
]
),
}}
Upvotes: 12
Reputation: 1733
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();
}
});
Upvotes: 5