我有3个实体Person
,PersonTagRelation
和Tag
:人员通过多对多关系与标签相关。
我还有一个dao,它具有查询数据库的多种功能。
大多数事情都运行良好,但是我有一个查询,该查询想创建一个具有特定标签的过滤用户列表,该标签无法正常工作。
例如,如果有3个人A
,B
,C
,其相应标签列表分别为[ai,ml]
,[ai]
,[flutter]
。那么我的查询应该返回
[A,B]
传递标签ai
时。但是它仅返回[A]
。
请签出以下代码,让我知道我哪里出了错:
Person.class
@Entity()
public class Person {
@PrimaryKey
private long presonID;
private String personName;
...
}
Tag.class
@Entity
public class Tag {
@PrimaryKey
private long tagID;
private String tagValue;
...
}
PersonTagRelation.class
@Entity(primaryKeys = {"personTagIDForPerson","personTagIDForTag"},
foreignKeys = {
@ForeignKey(entity = Person.class, parentColumns = "presonID", childColumns = "personTagIDForPerson"),
@ForeignKey(entity = Tag.class, parentColumns = "tagID", childColumns = "personTagIDForTag"),
})
public class PersonTagRelation {
private long personTagIDForPerson, personTagIDForTag;
...
}
PersonDao.class
@Dao
public abstract class PersonDao {
@Insert abstract void insertNewPerson(Person p);
@Insert abstract void insertNewTag(Tag t);
@Insert abstract void insertNewRelation(PersonTagRelation relation);
@Query("SELECT * FROM Person ORDER BY presonID DESC")
abstract List<Person> getAllPersons();
@Query("SELECT tagID FROM Tag WHERE tagValue=:tag ORDER BY tagID DESC")
abstract long getTagIdByTagName(String tag);
@Query("SELECT * FROM Person" +
" INNER JOIN PersonTagRelation ON Person.presonID=PersonTagRelation.personTagIDForPerson " +
"WHERE PersonTagRelation.personTagIDForTag=:tagID")
abstract List<Person> getAllPersonsForTagID(long tagID);
@Query("SELECT * FROM Tag " +
"INNER JOIN PersonTagRelation ON Tag.tagID=PersonTagRelation.personTagIDForTag " +
"WHERE PersonTagRelation.personTagIDForPerson=:personID")
abstract List<Tag> getAllTagsForPerson(long personID);
@Transaction
public void insertNewPersonTagData(UiModel model) {
insertNewPerson(model.getPerson());
for (Tag t : model.getTags()) {
insertNewTag(t);
insertNewRelation(new PersonTagRelation(model.getPerson().getPresonID(), t.getTagID()));
}
}
@Transaction
public List<UiModel> getFilteredModelList(String tag) {
List<UiModel> resultlist = new ArrayList<>();
long tagID = getTagIdByTagName(tag);
List<Person> filteredPersonList = getAllPersonsForTagID(tagID);
for (Person p : filteredPersonList) {
List<Tag> associatedTags = getAllTagsForPerson(p.getPresonID());
resultlist.add(new UiModel(p, associatedTags));
}
return resultlist;
}
@Transaction
public List<UiModel> getAllAsModelList() {
List<UiModel> modelList = new ArrayList<>();
List<Person> allpersons = getAllPersons();
for (Person p : allpersons) {
List<Tag> associatedTags = getAllTagsForPerson(p.getPresonID());
modelList.add(new UiModel(p, associatedTags));
}
return modelList;
}
UiModel.class
public class UiModel {
private Person person= new Person(System.currentTimeMillis(),"");
private List<Tag> tagList = new ArrayList<>();
public UiModel() {
}
}
图片1:getAllAsModelList()
的结果
图片2:通过getFilteredModelList()
时JS
的结果
更新:
@MikeT提供的测试套件非常好,但是事实证明数据库和查询功能是完全正确的。有关更多详细信息,请参见下面的答案。
答案 0 :(得分:0)
我相信您的问题是如何处理从 getFilteredModelList 方法返回的UiModel列表。
请考虑以下为调试目的添加的方法(在本示例中为添加到MainActivity.java中)。 :-
public static void logUiModel(List<UiModel> uiModelList) {
StringBuilder sb = new StringBuilder();
for (UiModel u: uiModelList) {
sb.append("\n\tUIModel Person ID = " + String.valueOf(u.getPerson().getPresonID()) + " Person Name = " + u.getPerson().getPersonName());
for (Tag t: u.getTags()) {
sb.append("\n\t\tTag ID =" + String.valueOf(t.getTagID()) + " Value = " + t.getTagValue());
}
}
Log.d("UIMODELINFO(LIST)",sb.toString());
}
public static void logUiModel(UiModel uiModel) {
StringBuilder sb = new StringBuilder().append("\nUIMODEL Person ID = " +String.valueOf(uiModel.getPerson().getPresonID()) + " Person Name = " + uiModel.getPerson().getPersonName());
for (Tag t: uiModel.getTags()) {
sb.append("\n\t\tTag ID =" + String.valueOf(t.getTagID()) + " Value = " + t.getTagValue());
}
Log.d("UIMODELINFO",sb.toString());
}
public static void logPersons(List<Person> personList) {
StringBuilder sb = new StringBuilder().append("People are :-");
for (Person p: personList) {
sb.append("\n\tPerson ID is " + String.valueOf(p.getPresonID()) + " Name is" + p.getPersonName());
}
Log.d("PERSONINFO",sb.toString());
}
public static void logTags(List<Tag> tagList) {
StringBuilder sb = new StringBuilder().append("Tags are");
for (Tag t: tagList) {
sb.append("\n\tTag ID is " + String.valueOf(t.getTagID()) + " Value is " + t.getTagValue());
}
Log.d("TAGINFO",sb.toString());
}
以及 getFilteredModelList 方法的以下更改:-
@Transaction
public List<UiModel> getFilteredModelList(String tag) {
List<UiModel> resultList = new ArrayList<>();
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 = new UiModel(p,associatedTags);
Log.d("GETFLTRDMDLLST","UIModels are :-");
MainActivity.logUiModel(u);
resultList.add(u);
}
return resultList;
}
和以下测试代码(同样在MainActivity.java中):-
protected void onCreate(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();
StringBuilder sb = new StringBuilder().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);
}
}
private void addDataIfNone() {
List<Person> people = mPDB.personDao().getAllPersons();
if (people.size() > 0) return;
Person[] peopleToAdd = new Person[]{
new Person("A"),
new Person("B"),
new Person("C")
};
mPDB.personDao().insertNewPersons(peopleToAdd);
Tag[] tagsToAdd = new Tag[] {
new Tag("ai"),
new Tag("ML"),
new Tag("Flutter"),
new Tag("JS"),
new Tag("Kotlin"),
new Tag("Dart")
};
mPDB.personDao().insertNewTags(tagsToAdd);
PersonTagRelation[] ptr = new PersonTagRelation[]{
new PersonTagRelation(1,1),
new PersonTagRelation(1,2),
new PersonTagRelation(2,1),
new PersonTagRelation(3,3)
};
mPDB.personDao().insertNewRelations(ptr);
}
相关性越高,表明对于标记 ai 而言,提取了人 A 和 B :-
06-24 11:27:53.365 9889-9889/? D/TAGFILTERINF: Filtering with a TAG value of ai
06-24 11:27:53.366 9889-9889/? D/GETFLTRMDLLST: Processing TAG where value is ai ID is 1
06-24 11:27:53.367 9889-9889/? D/GETFLTRDMDLLST: Persons are :-
06-24 11:27:53.367 9889-9889/? D/PERSONINFO: People are :-
Person ID is 1 Name isA
Person ID is 2 Name isB
06-24 11:27:53.367 9889-9889/? D/GETFLTRDMDLLST: Tags are :-
06-24 11:27:53.367 9889-9889/? D/TAGINFO: Tags are
Tag ID is 1 Value is ai
Tag ID is 2 Value is ML
06-24 11:27:53.367 9889-9889/? D/GETFLTRDMDLLST: UIModels are :-
06-24 11:27:53.367 9889-9889/? D/UIMODELINFO: UIMODEL Person ID = 1 Person Name = A
Tag ID =1 Value = ai
Tag ID =2 Value = ML
06-24 11:27:53.367 9889-9889/? D/GETFLTRDMDLLST: Persons are :-
06-24 11:27:53.367 9889-9889/? D/PERSONINFO: People are :-
Person ID is 1 Name isA
Person ID is 2 Name isB
06-24 11:27:53.367 9889-9889/? D/GETFLTRDMDLLST: Tags are :-
06-24 11:27:53.367 9889-9889/? D/TAGINFO: Tags are
Tag ID is 1 Value is ai
06-24 11:27:53.367 9889-9889/? D/GETFLTRDMDLLST: UIModels are :-
06-24 11:27:53.367 9889-9889/? D/UIMODELINFO: UIMODEL Person ID = 2 Person Name = B
Tag ID =1 Value = ai
06-24 11:27:53.369 9889-9889/? D/UIMODELINFO(LIST): UIModel Person ID = 1 Person Name = A
Tag ID =1 Value = ai
Tag ID =2 Value = ML
UIModel Person ID = 2 Person Name = B
Tag ID =1 Value = ai
这是完整的PersonTagRelation类:-
@Entity(primaryKeys = {"personTagIDForPerson","personTagIDForTag"},
foreignKeys = {
@ForeignKey(entity = Person.class, parentColumns = "presonID", childColumns = "personTagIDForPerson"),
@ForeignKey(entity = Tag.class, parentColumns = "tagID", childColumns = "personTagIDForTag"),
})
public class PersonTagRelation {
private long personTagIDForPerson, personTagIDForTag;
public PersonTagRelation() {
}
public PersonTagRelation(long personTagIDForPerson, long personTagIDForTag) {
this.personTagIDForPerson = personTagIDForPerson;
this.personTagIDForTag = personTagIDForTag;
}
public long getPersonTagIDForPerson() {
return personTagIDForPerson;
}
public void setPersonTagIDForPerson(long personTagIDForPerson) {
this.personTagIDForPerson = personTagIDForPerson;
}
public long getPersonTagIDForTag() {
return personTagIDForTag;
}
public void setPersonTagIDForTag(long personTagIDForTag) {
this.personTagIDForTag = personTagIDForTag;
}
}
答案 1 :(得分:0)
事实证明,这是我的愚蠢ui的过错。每次添加标签时,我都会生成一个新的ID,即使该标签已经存在。因此,如果我的数据库具有以下条目(从外观上):
Person --- Tags
A --- ai ,ml
B --- ml
C --- flutter
实际上是这个:
id---person id---tag id_person-----------id_tag
101 - A 11 - ai 101 -- 11
102 - B 12 - ml 101 -- 12
103 - C 13 - ml //! wrong 102 -- 13 //wrong!!
14 - flutter 103 -- 14
我的ui在将其添加为新标签之前没有检查天气是否存在标签。这就是getFilteredModelList()
函数无法生成包含多个条目的列表的原因。所以我最终为此写了一个额外的检查代码。此外,Dao最终进行了以下更改(对所有三个内部插入函数进行了额外的onConflict检查):
@Dao
public abstract class PersonDao {
private static final String TAG = "personDao>>";
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract void insertNewPerson(Person... p);
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract void insertNewTag(Tag... t);
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract void insertNewRelation(PersonTagRelation... relation);
...
}