Skip to main content

Links

Links allow you to express relationships between objects โ€” such as the author (User) of a Comment, or the Post the comment belongs to.

IsarLink#

IsarLink<T> can contain zero or one related objects so it can be used to express a to-one relationship. IsarLink has a single property called value which holds the linked object.

Links are lazy so you need to explicitly tell the IsarLink to load or save the value. You can do this by calling linkProperty.load() and linkProperty.save().

Let's start by adding an IsarLink to a collection:

@IsarCollection()
class Teacher {
int id;
String subject;
}
@IsarCollection()
class Student {
int id;
String name;
final teachers = IsarLink<Teacher>();
}

We defined a link between teachers and students. Every student can have exactly one teacher in this example.

final mathTeacher = Teacher()..subject = 'Math';
final linda = Student()
..name = 'Linda'
..teachers.value = mathTeacher;
await isar.writeTxn((isar) async {
await isar.students.put(linda);
await linda.teachers.save();
});

First we create a math teacher, then we assign it to a student. As you can see in this example, we have to put() the student manually (obviously) but the isar link takes care of inserting the teacher.

IsarLinks#

It would make more sense if the student from the previous example could have multiple teachers. Fortunately Isar has IsarLinks<T> which can contain multiple related objects and express a to-many relationship.

IsarLinks<T> extends Set<T> so it exposes all the methods that are allowed for sets.

IsarLinks behaves much like IsarLink and is also lazy. To load all linked object call linkProperty.load(). To persist the changes call linkProperty.saveChanges().

Internally both IsarLink and IsarLinks are represented in the same way. This allows us to upgrade the IsarLink<Teacher> from before to an IsarLinks<Teacher> to assign multiple teachers to a single student.

@IsarCollection()
class Student {
int id;
String name;
final teachers = IsarLinks<Teacher>();
}

This works because we did not change the name of the link (teachers) so Isar remembers it from before.

final englishTeacher = Teacher()..subject = 'English';
final linda = isar.students.where().filter().nameEqualTo('Linda').findFirst();
await linda.teachers.load();
print(linda.teachers); // {Teacher('Math')}
linda.teachers.insert(englishTeacher);
await isar.writeTxn((isar) async {
await linda.teachers.saveChanges();
});
print(linda.teachers); // {Teacher('Math'), Teacher('English')}

Backlinks#

I hear you ask "What if we want to express reverse relationships?". Don't worry, we'll now introduce backlinks.

Backlinks are links in reverse direction. Each link always has an implicit backlink. You can make it available to your app by annotating an IsarLink or IsarLinks with @Backlink().

Backlinks do not require additional memory or resources and you can freely add, remove and rename them without loosing data.

We want to know which students a specific teacher has so we define a backlink:

@IsarCollection()
class Teacher {
int id;
String subject;
@Backlink(to: 'teachers')
final students = IsarLinks<Student>();
}

We need to specify the link to which the backlink points. It is possible to have multiple different links between two objects.

Initialize links#

IsarLink and IsarLinks both have a zero-arg constructor which should be used to assign the link property when the object is created. It is good practice to make link properties final.

When you put() your object for the first time, the link gets initialized with source and target collection and you can call methods like load(), save() and saveChanges().

It is illegal to move a link to another object and will lead to undefined behavior.