使用 Room 的 @Relation 和 ORDER BY

Using Room's @Relation with ORDER BY

我试用了 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 和存储库。

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

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

有什么想法吗?

谢谢。

我认为当前版本的 Room 中没有内置的方法来执行此操作。

我可以提出两种可能的解决方案。

  1. 而不是使用 @Relation 的 POJO,只需使用两个单独的查询来获取您的对象。这样您就可以完全按照自己喜欢的方式订购 StepEntity 实例。当你得到 ColisEntity 和所有有序对应的 StepEntity 记录时,你可以在你的 repo 层中构造一个 ColisWithSteps 对象并 return 它。
  2. 您可以创建一个数据库视图,按所需顺序对 StepEntity 记录进行排序,然后使用此答案 以便能够使用它。

我认为选项 1 最适合您的情况 - 是的,它将涉及使用两个查询,但至少它不会破坏您的数据库迁移,并且您将能够使用 Room 来发挥自己的优势。

我知道 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;
       }
    }

这是在房间 v1.0.0 中应用关系排序的工作解决方案。

我用 Kotlin 写过

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

这里是 Java 版本:

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

已更新 ColisWithSteps class:

public class ColisWithSteps {
        @Embedded
        public ColisEntity colisEntity;

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

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

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

下面是一个解释 INNER JOIN 作用的例子:

To query data from multiple tables, you use INNER JOIN clause. The INNER JOIN clause combines columns from correlated tables.

Suppose you have two tables: A and B.

A has a1, a2, and f columns. B has b1, b2, and f column. The A table links to the B table using a foreign key column named f. For each row in the A table, the INNER JOIN clause compares the value of the f column with the value of the f column in the B table. If the value of the f column in the A table equals the value of the f column in the B table, it combines data from a1, a2, b1, b2, columns and includes this row in the result set.

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

documentation for Relationships 给出了有关其工作原理的提示

This method requires Room to run two queries, so add the @Transaction annotation to this method to ensure that the whole operation is performed atomically.

这有效地泄露了关系背后的整个过程。您必须为每个实体编写一个查询,然后是一个事务查询,但最终结果与使用关系所获得的结果无法区分(至少在我看来是这样)。

您的(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) 将 return 正是您要查找的内容,结果与 Relation 给您的结果相同,只是排序更加自由。