使用Room的@Relation和ORDER BY

时间:2018-01-18 06:42:24

标签: android android-room

我试试房间图书馆,顺便说一句,这是一个令人印象深刻的图书馆!

所以我有两个@Entity和一个由两个实体组成的POJO。

我的第一个实体=>

    @Entity(tableName = "colis")
      public class ColisEntity {
        @PrimaryKey
        private String idColis;
        private String label;
      }  

我的第二个实体带有外键=>

    @Entity(tableName = "step",
                foreignKeys = @ForeignKey(entity = ColisEntity.class,
 parentColumns = "idColis",
 childColumns = "idColis",
 onDelete = CASCADE))
        public class StepEntity {

            @PrimaryKey(autoGenerate = true)
            private Integer idStep;
            private String idColis;
            private Long date;
        }

我的POJO与@Relation

public class ColisWithSteps {
        @Embedded
        public ColisEntity colisEntity;

        @Relation(parentColumn = "idColis", entityColumn = "idColis")
        public List<StepEntity> stepEntityList;
    }

所有这些东西都适用于我的@Dao和Repositories。

但我希望我的@Relation列表按日期排序,我不希望StepEntity实现Comparable并制作Collections.sort()。

因为我认为排序应该由数据库完成,而不是在查询之后。

有什么想法吗?

感谢。

5 个答案:

答案 0 :(得分:2)

documentation for Relationships提示了它的工作方式

此方法需要Room运行两个查询,因此请向该方法添加@Transaction批注,以确保整个操作都是原子执行的。

这有效地消除了关系正在做什么的整个过程。您必须为每个实体编写一个查询,然后是一个事务查询,但是最终结果与使用关系所得到的结果是无法区分的(至少据我所知)。

您的(Kotlin)代码如下:

@Query("SELECT * FROM colis WHERE idColis = :id")
fun getColisEntity(id : Int) : 

@Query("SELECT * FROM step WHERE idColis = :id ORDER BY date")
fun getStepEntities(id : Int) : List<StepEntity> 

@Transaction
fun getColisWithSteps(id : Int) : ColisWithSteps{
    return ColisWithSteps(getColisEntity(id), getStepEntities(id))                      
}

getColisWithSteps(id : Int)会完全返回您要查找的内容,其结果与Relation所提供的内容相同,只是订购的自由度更高。

答案 1 :(得分:1)

以下是在房间v1.0.0中使用Relation进行排序的工作解决方案。

我写过kotlin

@Query("SELECT * FROM colis INNER JOIN step ON colis.idColis= step.idColis ORDER BY date DESC")
fun getAllColisWithSteps():Flowable<List<ColisWithSteps>>

这是jave版本:

 @Query("SELECT * FROM colis INNER JOIN step ON colis.idColis= step.idColis ORDER BY date DESC")
public List<ColisWithSteps> getAllColisWithSteps()

更新了ColisWithSteps类:

public class ColisWithSteps {
        @Embedded
        public ColisEntity colisEntity;

        @Relation(parentColumn = "idColis", entityColumn = "idColis",entity = StepEntity.class)
        public List<StepEntity> stepEntityList;
    }

答案 2 :(得分:0)

我认为在当前版本的Room中有一种内置的方法可以做到这一点。

我可以建议两种可能的解决方案。

  1. 使用两个单独的查询来获取对象,而不是使用@Relation的POJO。这样您就可以按照自己喜欢的方式订购StepEntity个实例。当您获得ColisEntity和所有已排序的相应StepEntity条记录时,您可以在回购图层中构建ColisWithSteps对象并将其返回。
  2. 您可以创建一个数据库视图,按所需顺序排序StepEntity条记录,然后使用此答案Views in Room即可使用它。
  3. 我认为选项1在您的情况下是最好的 - 是的,它将涉及使用两个查询,但至少它不会破坏您的数据库迁移,您将能够利用Room来发挥优势。 / p>

答案 3 :(得分:0)

我知道OP对Collection.Sort()说不,但考虑到情况,这似乎是最干净的方法。正如我上面所说,我认为最好避免每次需要访问数据时都要进行单独的查询。首先实现Comparable。

public class StepEntity implements Comparable<StepEntity >{
    @PrimaryKey(autoGenerate = true)
    private Integer idStep;
    private String idColis;
    private Long date;

   @Override
    public int compareTo(@NonNull StepEntity stepEntity ) {
        int dateOther = stepEntity.date;

        //ascending order
        return this.date - dateOther;

       //descending order
       //return dateOther - this.date;
    }
}

现在使用它在现有的@Relation POJO

中添加一个方法包装器
public class ColisWithSteps {
        @Embedded
        public ColisEntity colisEntity;

        @Relation(parentColumn = "idColis", entityColumn = "idColis")
        public List<StepEntity> stepEntityList;

        //add getter method
        public List<StepEntity> getSortedStepEntityList(){
           Collections.Sort(stepEntityList);
           return stepEntityList;
       }
    }

答案 4 :(得分:0)

我遇到了同样的问题,这是一个解决方案:

@Query("SELECT * FROM step INNER JOIN colis ON step.idColis = colis.idColis ORDER BY date DESC")
fun getAllColisWithSteps():LiveData<List<ColisWithSteps>>

下面是一个示例,解释了INNER JOIN的作用:

  

要从多个表中查询数据,请使用INNER JOIN子句。的   INNER JOIN子句组合了相关表中的列。

     

假设您有两个表:A和B。

     

A具有a1,a2和f列。 B具有b1,b2和f列。 A表   使用名为f的外键列链接到B表。   对于A表中的每一行,INNER JOIN子句将f列的值与B表中f列的值进行比较。如果A表中的f列的值等于B表中的f列的值,则它将a1,a2,b1,b2列中的数据合并,并将该行包括在结果集中。

     

https://www.sqlitetutorial.net/sqlite-inner-join/