Skip to content Skip to sidebar Skip to footer

Room Db With Many To Many Relations : Returns Single Entry On Querying For Filtered Data

I have 3 enitities Person, PersonTagRelation and Tag : Person is related to a tag via many to many relation. I also have a single dao for having multiple functions for querying db.

Solution 1:

I believe that your issue is how you are processing the UiModel list returned from the getFilteredModelList method.

Consider the following methods added for debugging purposes (in this example case, added to MainActivity.java). :-

publicstaticvoidlogUiModel(List<UiModel> uiModelList) {
    StringBuilder sb = newStringBuilder();
    for (UiModelu: uiModelList) {
        sb.append("\n\tUIModel Person ID = " + String.valueOf(u.getPerson().getPresonID()) + " Person Name = " + u.getPerson().getPersonName());
        for (Tagt: u.getTags()) {
            sb.append("\n\t\tTag ID =" + String.valueOf(t.getTagID()) + " Value = " + t.getTagValue());
        }
    }
    Log.d("UIMODELINFO(LIST)",sb.toString());
}

publicstaticvoidlogUiModel(UiModel uiModel) {
    StringBuilder sb = newStringBuilder().append("\nUIMODEL Person ID = " +String.valueOf(uiModel.getPerson().getPresonID()) + " Person Name = " + uiModel.getPerson().getPersonName());
    for (Tagt: uiModel.getTags()) {
        sb.append("\n\t\tTag ID =" + String.valueOf(t.getTagID()) + " Value = " + t.getTagValue());
    }
    Log.d("UIMODELINFO",sb.toString());
}

publicstaticvoidlogPersons(List<Person> personList) {
    StringBuilder sb = newStringBuilder().append("People are :-");
    for (Personp: personList) {
        sb.append("\n\tPerson ID is " + String.valueOf(p.getPresonID()) + " Name is" + p.getPersonName());
    }
    Log.d("PERSONINFO",sb.toString());
}

publicstaticvoidlogTags(List<Tag> tagList) {
    StringBuilder sb = newStringBuilder().append("Tags are");
    for (Tagt: tagList) {
        sb.append("\n\tTag ID is " + String.valueOf(t.getTagID()) + " Value is " + t.getTagValue());
    }
    Log.d("TAGINFO",sb.toString());
}

And the following changes to the getFilteredModelList method :-

@TransactionpublicList<UiModel> getFilteredModelList(String tag) {
    List<UiModel> resultList = newArrayList<>();
    long tagID = getTagIdByTagName(tag);
    Log.d("GETFLTRMDLLST","Processing TAG where value is " + tag + " ID is " + String.valueOf(tagID));
    List<Person> filteredPersonList = getAllPersonsForTagID(tagID);

    for (Person p : filteredPersonList) {
        Log.d("GETFLTRDMDLLST","Persons are :-");
        MainActivity.logPersons(filteredPersonList);
        List<Tag> associatedTags = getAllTagsForPerson(p.getPresonID());
        Log.d("GETFLTRDMDLLST","Tags are :-");
        MainActivity.logTags(associatedTags);
        UiModel u = newUiModel(p,associatedTags);
        Log.d("GETFLTRDMDLLST","UIModels are :-");
        MainActivity.logUiModel(u);
        resultList.add(u);
    }
    return resultList;
}

and the following testing code (again in MainActivity.java) :-

protectedvoidonCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mPDB = Room.databaseBuilder(this,PersonDatabase.class,"person.db").allowMainThreadQueries().build();
    addDataIfNone();
    List<Person> allPeople = mPDB.personDao().getAllPersons();
    logPersons(allPeople);
    List<Tag> allTags1 = mPDB.personDao().getAllTags();
    logTags(allTags1);
    List<PersonTagRelation> allPTRs = mPDB.personDao().getAllPersonTagRelations();
    logPersonTagRelations(allPTRs);
    List<UiModel> uiModelList = mPDB.personDao().getAllAsModelList();
    StringBuildersb=newStringBuilder().append("UIMODELS are :-");
    for (UiModel u: uiModelList) {
        sb.append("\n\tPerson ID = " + String.valueOf(u.getPerson().getPresonID()) + " Name = " + u.getPerson().getPersonName());
        for (Tag t: u.getTagList()) {
            sb.append("\n\t\tTag ID = " + String.valueOf(t.getTagID()) + " Value = " + t.getTagValue());
        }
    }
    Log.d("UIMODELINFO",sb.toString());

    List<Tag> allTags = mPDB.personDao().getAllTags();
    List<UiModel> uiListOfModelsViaFilter;
    for (Tag t: allTags) {
        Log.d("TAGFILTERINF","Filtering with a TAG value of " + t.getTagValue() );
        uiListOfModelsViaFilter = mPDB.personDao().getFilteredModelList(String.valueOf(t.getTagValue()));
        logUiModel(uiListOfModelsViaFilter);
    }
}

privatevoidaddDataIfNone() {
    List<Person> people = mPDB.personDao().getAllPersons();
    if (people.size() > 0) return;

    Person[] peopleToAdd = newPerson[]{
            newPerson("A"),
            newPerson("B"),
            newPerson("C")
    };
    mPDB.personDao().insertNewPersons(peopleToAdd);

    Tag[] tagsToAdd = newTag[] {
            newTag("ai"),
            newTag("ML"),
            newTag("Flutter"),
            newTag("JS"),
            newTag("Kotlin"),
            newTag("Dart")
    };
    mPDB.personDao().insertNewTags(tagsToAdd);

    PersonTagRelation[] ptr = newPersonTagRelation[]{
            newPersonTagRelation(1,1),
            newPersonTagRelation(1,2),
            newPersonTagRelation(2,1),
            newPersonTagRelation(3,3)
    };
    mPDB.personDao().insertNewRelations(ptr);
}

The the more pertinent out shows that for tag ai that persons A and B are extracted :-

06-2411:27:53.3659889-9889/?D/TAGFILTERINF:FilteringwithaTAGvalueofai06-2411:27:53.3669889-9889/?D/GETFLTRMDLLST:ProcessingTAGwherevalueisaiIDis106-2411:27:53.3679889-9889/?D/GETFLTRDMDLLST:Personsare:-06-2411:27:53.3679889-9889/?D/PERSONINFO:Peopleare:-PersonIDis1NameisAPersonIDis2NameisB06-2411:27:53.3679889-9889/?D/GETFLTRDMDLLST:Tagsare:-06-2411:27:53.3679889-9889/?D/TAGINFO:TagsareTagIDis1ValueisaiTagIDis2ValueisML06-2411:27:53.3679889-9889/?D/GETFLTRDMDLLST:UIModelsare:-06-2411:27:53.3679889-9889/?D/UIMODELINFO:UIMODELPersonID=1PersonName=ATagID=1Value=aiTagID=2Value=ML06-2411:27:53.3679889-9889/?D/GETFLTRDMDLLST:Personsare:-06-2411:27:53.3679889-9889/?D/PERSONINFO:Peopleare:-PersonIDis1NameisAPersonIDis2NameisB06-2411:27:53.3679889-9889/?D/GETFLTRDMDLLST:Tagsare:-06-2411:27:53.3679889-9889/?D/TAGINFO:TagsareTagIDis1Valueisai06-2411:27:53.3679889-9889/?D/GETFLTRDMDLLST:UIModelsare:-06-2411:27:53.3679889-9889/?D/UIMODELINFO:UIMODELPersonID=2PersonName=BTagID=1Value=ai06-2411:27:53.3699889-9889/?D/UIMODELINFO(LIST):UIModelPersonID=1PersonName=ATagID=1Value=aiTagID=2Value=MLUIModelPersonID=2PersonName=BTagID=1Value=ai

Edit

This is the full PersonTagRelation class :-

@Entity(primaryKeys = {"personTagIDForPerson","personTagIDForTag"},
        foreignKeys = {
                @ForeignKey(entity = Person.class, parentColumns = "presonID", childColumns = "personTagIDForPerson"),
                @ForeignKey(entity = Tag.class, parentColumns = "tagID", childColumns = "personTagIDForTag"),
        })
publicclassPersonTagRelation {
    privatelong personTagIDForPerson, personTagIDForTag;

    publicPersonTagRelation() {
    }

    publicPersonTagRelation(long personTagIDForPerson, long personTagIDForTag) {
        this.personTagIDForPerson = personTagIDForPerson;
        this.personTagIDForTag = personTagIDForTag;
    }

    publiclonggetPersonTagIDForPerson() {
        return personTagIDForPerson;
    }

    publicvoidsetPersonTagIDForPerson(long personTagIDForPerson) {
        this.personTagIDForPerson = personTagIDForPerson;
    }

    publiclonggetPersonTagIDForTag() {
        return personTagIDForTag;
    }

    publicvoidsetPersonTagIDForTag(long personTagIDForTag) {
        this.personTagIDForTag = personTagIDForTag;
    }
}
  • Note the constructor that takes the two values (and how it is used in the addDataIfNone method).

Solution 2:

As it turns out , it was my silly ui at fault. I was generating a new id every time i add a tag, even if its already present. thus if my DB has the following entries(from what it looks like):

Person --- Tags
A      --- ai ,ml
B      --- ml
C      --- flutter

it was actually this :

id---person     id---tag        id_person-----------id_tag101 -  A11 - ai             101      --       11102 -  B12 - ml             101      --       12103 -  C        13 - ml //! wrong   102      --       13 //wrong!!  
                14 - flutter        103      --       14

My ui was not checking weather a tag existed before adding it as new tag. That's why the getFilteredModelList() function was not able to generate a list with more than 1 entry. so i ended up writing an extra checker code for that. Also, the dao ended up with the following mini change( an extra onConflict check for all three internal insertion functions):

@DaopublicabstractclassPersonDao {
    privatestaticfinalStringTAG="personDao>>";

    @Insert(onConflict = OnConflictStrategy.REPLACE)abstractvoidinsertNewPerson(Person... p); 

    @Insert(onConflict = OnConflictStrategy.REPLACE)abstractvoidinsertNewTag(Tag... t);          

    @Insert(onConflict = OnConflictStrategy.REPLACE)abstractvoidinsertNewRelation(PersonTagRelation... relation);  

    ...
    }

Post a Comment for "Room Db With Many To Many Relations : Returns Single Entry On Querying For Filtered Data"