2

I am currently creating a database using Isar that looks like this:


@collection
class Polygon {
  Id id = Isar.autoIncrement;

  final vertices = IsarLinks<Vertex>();

  late Color color;
}

@collection
class Vertex {
  Id id = Isar.autoIncrement;

  final polygon = IsarLink<Polygon>();

  late Offset point;
}

In my code, I've got an image I'm drawing these polygons onto using a GestureDetector onTapUp event to do:

List<Vertex>? _currentVertices;

void addVertex(details) async {
    Offset pos = details.localPosition;

    if (_currentVertices == null) {
      _currentVertices = [Vertex()..point = pos];
    } else {
      if (_currentVertices!.length > 2 &&
        (_currentVertices!.first.point - pos).distance <= 20 ) {

        // Create a new polygon from the list of vertices and save it to the database
        Polygon p = Polygon();

        // Set the polygon for each vertex
        for (var v in _currentVertices!) {
          v.polygon.value = p;
        }

        // Save it into the database
        await _isar.writeTxn(() async {
          await _isar.polygons.put(p);
        });

        _currentVertices = null;
      } else {
        // Add point to current list of vertices
        _currentVertices!.add(Vertex()..point = pos);
      }
    }
  }

But, when I do this, the Polygon will appear in the database, but the vertices do not. So I tried:

    await _isar.writeTxn(() async {
      await _isar.polygons.put(p);
    });

    for (var v in _currentVertices!) {
      await _isar.writeTxn(() async {
        await _isar.vertexs.put(v);
      });
    }

Now both the polygons and the vertices are in the database, but the id's / IsarLinks are not set...

  1. Does anyone have an example of how you should do this?

Secondly:

I've actually been reading about instead using a provider here (inside a PolygonModel class). So once I have my PolygonModel class (that my view can watch for changes to the polygons), I need to have a method PolygonModel.addPolygon(p).

Should I implement both the Polygon model and Vertex model? I don't actually need a Vertex model as a change notifier, so it feels like overkill. So should I just do:

        // Create a new polygon from the list of vertices and save to the database
        Polygon p = Polygon();

        for (var v in _currentVertices!) {
          v.polygon.value = p;
        }

        // Add both the polygon and vertices to the database
        polygonModel.addPolygon(p, _currentVertices!);

Or do I actually need to do something like:

        // Create a new polygon from the list of vertices and save to the database
        Polygon p = Polygon();

        polygonModel.addPolygon(p);

        for(var v in _currentVertices!) {
          vertexModel.addVertex(p, v);
        }

Again, any links to suitable examples of a similar implementation would be great (currently I was going to use provider/provider.dart, but have also been reading about Riverpod, which may be a better solution).

1 Answers1

0

Ok, I think I've solved this problem, the real issue is that I changed from using synchronous to asynchronous transactions...

Isar automatically saves any IsarLinks in a component when you use a synchronous transaction, it doesn't with an asynchronous one... So part of the solution is to correctly save the IsarLink elements of a component when you save the component. So if, for example, I had a parent component of the polygon component such that there was a one-to-one relationship, you'd do:

        // Save it into the database
        await _isar.writeTxn(() async {
          await _isar.parents.put(parent);
          await parent.polygon.save();
        });

This will save the new parent into the isar database and then save the IsarLink to the polygon (where there is one polygon per parent).

To solve the issue with the IsarLinks to Vertex, I took the easy way out and used an embedded instead:

@collection
class Parent {
  Id id = Isar.autoIncrement;
  final polygon = IsarLink<Polygon>();
}

@collection
class Polygon {
  Id id = Isar.autoIncrement;

  List<Vertex>? vertices;
}

@embedded
class Vertex {
  late double x;
  late double y;
}

It's not really cheating, because this is the right way to do this kind of thing (Vertexs aren't shared between different Polygons). But also means I skirt around the save'ing of IsarLinks. But I'll come back to that sometime later... Comments would be useful.

Second issue:

Again here, I've used the simplest solution. Since the Vertexs are actually now just a list of 'embedded' then they get saved automatically along with the Polygon. I'm not sure I've really answered my own questions, but hopefully, someone else can learn from my thoughts here.