相关文章推荐
从容的路灯  ·  机器学习 ...·  11 月前    · 
留胡子的楼梯  ·  正则表达式 ...·  1 年前    · 

Android Room JOIN查询将结果分割成大小为1的列表。

0 人关注

我有2个安卓室表book和persons。每本书都有一个外键,叫做owner_id,它把它分配给一个人的实体。 我现在试图得到一个地图,给我一个书与每个人的列表。

为此,我在我的DAO类中使用这个方法。

@Transaction
@Query("SELECT * FROM books JOIN persons ON persons.id = book.owner_id")
public abstract Map<Person, List<Book>> getMap();

这将返回一个像这样的地图。

而不是我的理想结果。

我的房间班级是这样的。

@Entity
public class Person {
    @NonNull
    @PrimaryKey
    public UUID id;
    public String name="";
    @Override
    public boolean equals(@Nullable Object obj) {
        if(obj instanceof  Person)
            return ((Person) obj).equals(id);
        return super.equals(obj);
    @Override
    public int hashCode() {
        return id.hashCode();
@Entity
public class Book {
    @NonNull
    @PrimaryKey
    public UUID id;
    public UUID owner_id;
    public String name="";
    @Override
    public boolean equals(@Nullable Object obj) {
        if(obj instanceof  Book)
            return ((Book) obj).equals(id);
        return super.equals(obj);
    @Override
    public int hashCode() {
        return id.hashCode();
@Database(entities = {Person.class,Book.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class LibarayDB extends RoomDatabase {
    public abstract LibarayDBdao libarayDBdao();

我怎样才能使返回的地图只包含关键的Person X一次,并有一个列表的 书籍A和书籍B作为一个值?

android
sql
android-room
spam junk
spam junk
发布于 2022-10-05
1 个回答
MikeT
MikeT
发布于 2022-10-06
已采纳
0 人赞同

你使用一个嵌入了 Person 成员的POJO,即注释了 @Embedded 和一个与List相关的,即注释了 @Relation

You then use an @Query , preceded by @Transaction , to SELECT the respective Person s (no need for the JOIN ) returning a List<> of the POJO.

作为一个例子:-

class PersonWithListOfRelatedBooks {
   @Embedded
   Person person;
   @Relation(
           entity = Book.class,
           parentColumn = "id",
           entityColumn = "owner_id"
   List<Book> bookList;
@Transaction
@Query("SELECT * FROM person")
List<PersonWithListOfRelatedBooks> getPersonWithRelatedBooks();

Using code modified for convenience

  • Longs for id's so no need for type converters
  • .allowMainThreadQueries, so can run on the main thread
  • The Book类:-

    @Entity(
            /* ADDED as a suggestion (enforces referential integrity) */
            /* NOTE will fail if child(Book) is added without a parent (Person) */
            foreignKeys = {
                    @ForeignKey(
                            entity = Person.class,
                            parentColumns = {"id"},
                            childColumns = {"owner_id"},
                            /* Optional but helps to maintain referential integrity */
                            onDelete = ForeignKey.CASCADE,
                            onUpdate = ForeignKey.CASCADE
    public class Book {
        @NonNull
        @PrimaryKey
        public Long id; /* CHANGED FOR convenience */
        @ColumnInfo
        public Long owner_id; /* CHANGED FOR convenience */
        public String name="";
        @Override
        public boolean equals(@Nullable Object obj) {
            if(obj instanceof  Book)
                return ((Book) obj).equals(id);
            return super.equals(obj);
        @Override
        public int hashCode() {
            return id.hashCode();
    

    The Person类:-

    @Entity
    public class Person {
       @NonNull
       @PrimaryKey
       public Long id;  /* CHANGED FOR convenience */
       public String name="";
       @Override
       public boolean equals(@Nullable Object obj) {
          if(obj instanceof  Person)
             return ((Person) obj).equals(id);
          return super.equals(obj);
       @Override
       public int hashCode() {
          return id.hashCode();
    

    The 利巴雷道接口 :-

    interface LibarayDBdao { @Insert(onConflict = OnConflictStrategy.IGNORE) long insert(Person person); @Insert(onConflict = OnConflictStrategy.IGNORE) long insert(Book book); @Transaction @Query("SELECT * FROM person") List<PersonWithListOfRelatedBooks> getPersonWithRelatedBooks();

    The 有相关书籍的人的名单(PersonWithListOfRelatedBooks类(同上)。

    The 利巴雷数据库 abstract类:-

    @Database(entities = {Person.class,Book.class}, version = 1, exportSchema = false /* ADDED to suppress warning */)
    //@TypeConverters({Converters.class}) /* Commented out for convenience */
    public abstract class LibarayDB extends RoomDatabase {
        public abstract LibarayDBdao libarayDBdao();
        private static volatile LibarayDB instance;
        public static LibarayDB getInstance(Context context) {
            if (instance==null) {
                instance = Room.databaseBuilder(context,LibarayDB.class,"libaray.db")
                        .allowMainThreadQueries() /* for convenience and brevity of the demonstration */
                        .build();
            return instance;
    

    一些活动代码:-

    public class MainActivity extends AppCompatActivity {
        LibarayDB db;
        LibarayDBdao dao;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            db = LibarayDB.getInstance(this);
            dao = db.libarayDBdao();
            Person personX = new Person();
            personX.name = "PersonX";
            long personXId = dao.insert(personX);
            Book book = new Book();
            book.name = "BookA";
            book.owner_id = personXId;
            dao.insert(book);
            book.name = "BookB";
            dao.insert(book);
            StringBuilder sb = new StringBuilder();
            for(PersonWithListOfRelatedBooks pwrb: dao.getPersonWithRelatedBooks()) {
                for (Book b: pwrb.bookList) {
                    sb.append("\n\tBook is " + b.name);
                Log.d("DBINFO","Person is " + pwrb.person.name + " and has " + pwrb.bookList.size() + " books:-" + sb);
    

    RESULT(作为对日志的输出) :-

    D/DBINFO: Person is PersonX and has 2 books:-
            Book is BookA
            Book is BookB