1

I am trying to achieve many-to-many relationship in Room Persistence Library. I am trying to create a Notes App with Tags.

The idea is:

  • A note will have multiple tags.

  • A tag will have multiple notes.

  • Show all notes in RecyclerView along with Tags.

To achieve this, I have created two models Note.java, Tag.java and TagJoin model to store the relationship b/w notes and tags. Achieving one-to-one is very easy using @Relation annotation.

Here are my models

@Entity(tableName = "notes")
public class Note {
    @PrimaryKey
    @NonNull
    public final String id;

    @ColumnInfo(name = "note")
    public String note;

    @Ignore
    public List<Tag> tags;

    @Ignore
    public Note(String note) {
        this(UUID.randomUUID().toString(), note);
    }

    public Note(String id, String note) {
        this.id = id;
        this.note = note;
    }

    public String getId() {
        return id;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public List<Tag> getTags() {
        return tags;
    }

    public void setTags(List<Tag> tags) {
        this.tags = tags;
    }

    @Entity(tableName = "note_tag_join",
            primaryKeys = {"noteId", "tagId"},
            foreignKeys = {
                    @ForeignKey(
                            entity = Note.class,
                            parentColumns = "id",
                            childColumns = "noteId",
                            onDelete = CASCADE),
                    @ForeignKey(
                            entity = Tag.class,
                            parentColumns = "id",
                            childColumns = "tagId",
                            onDelete = CASCADE)},
            indices = {
                    @Index(value = "noteId"),
                    @Index(value = "tagId")
            }
    )

    public static class TagJoin {
        @NonNull
        public final String noteId;
        @NonNull
        public final String tagId;

        public TagJoin(String noteId, String tagId) {
            this.noteId = noteId;
            this.tagId = tagId;
        }
    }
}

Tags Model:

@Entity(tableName = "tags", indices = {@Index(value = "name", unique = true)})
public class Tag {
    @PrimaryKey
    @NonNull
    public String id;

    @ColumnInfo(name = "name")
    public String name;

    @Ignore
    public Tag(String name) {
        this(UUID.randomUUID().toString(), name);
    }

    public Tag(String id, String name) {
        this.id = id;
        this.name = name;
    }


    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Notes Dao:

@Dao
public interface NoteDao {

    @Query("SELECT * FROM notes ORDER BY id DESC")
    LiveData<List<Note>> getAllNotes();

    @Insert
    long insert(Note note);

    @Update
    void update(Note note);

    @Delete
    void delete(Note note);

    @Query("DELETE FROM notes")
    void deleteAll();

    @Query("SELECT COUNT(*) FROM notes")
    int getNotesCount();

    @Query("SELECT notes.* FROM notes\n" +
            "INNER JOIN note_tag_join ON notes.id=note_tag_join.noteId\n" +
            "WHERE note_tag_join.tagId=:tagId")
    List<Note> getAllNotesOfTag(String tagId);

    @Insert
    void insert(Note.TagJoin... joins);

    @Delete
    void delete(Note.TagJoin... joins);
}

So far everything is good. Now I want to show the Notes in RecyclerView but I can't find a way to fetch all Notes along with Tags at once. One way is, getting the tags of each note in onBindViewHolder method which I think is wrong as we have to query the db each time row is displayed.

Please provide me suggestions.

PS: I have followed the code provided in this article https://commonsware.com/AndroidArch/previews/mn-relations-in-room

Minion
  • 565
  • 1
  • 7
  • 23
  • "I can't find a way to fetch all Notes along with Tags at once" -- Room doesn't do much in the way of retrieving related objects "at once". You could try using `@Relation`. Or, write a method on your `@Dao` that fetches everything that you want and stitches them together. "I have followed the code provided in this article" -- FYI, that is not an article. It is a preview edition of a chapter from [this book](https://commonsware.com/AndroidArch). – CommonsWare Apr 24 '18 at 20:18
  • Thank you @CommonsWare I'll try and find a way out. – Minion Apr 25 '18 at 03:25
  • This might be helpful https://stackoverflow.com/a/58424784 – Nischal Oct 21 '19 at 04:54

0 Answers0