将具有较少字段的新 POJO class 映射到现有房间 table

Map new POJO class with lesser fields to an existing Room table

目前,我们有以下 Dao 和模型 class。

NoteDao

@Query("SELECT * FROM note")
public abstract LiveData<List<Note>> getAllNotes();

备注class

@Entity(
    tableName = "note"
)
public class Note {
    @ColumnInfo(name = "title")
    private String title;

    // Can contain a huge String.
    @ColumnInfo(name = "body")
    private String body;
}

然而,在某些情况下,我们只对加载 title 感兴趣。

一次加载所有 Note 具有大 body 字符串,可能会导致 OutOfMemoryException

有什么办法,我们可以创建另一个 POJO,如下所示?

public class SimpleNote {
    private String title;
}

然后,我们可以从 NoteDao?

return 列表 SimpleNote
@Query("???")
public abstract LiveData<List<SimpleNote>> getAllSimpleNotes();

这对你有用:

@Query("SELECT title FROM note") 
LiveData<List<String>> getAllNoteTitles();

当您调用 SELECT * 时,它将 select table.

中的所有字段

即使不选择 body 列,也可以将其映射到 Note,而不是使用类型 String

@Query("SELECT title FROM note")
LiveData<List<Note>> getAllNotesPreview();

在 Room 中,@Entity 通常被映射 1:1 到 table,因为 ORM 很常见。因此,将两个对象自动映射到同一个 table 是不可能的。按列名选择确实似乎是最省力的,仅从那里读取时没有问题。对于 read/write 访问,仍然需要记录的完整详细信息视图,其中包含所有列。


尽管提供的代码看起来很像 Java,但在 Kotlin 中也可能是:

@Query("SELECT title FROM note")
Flow<List<Note>> getAllNotesPreview();

这将排除突变,这在并非所有列都已被查询和映射时才有意义。否则它可能只会空白缺席的 body 列,例如。编辑 title 列。请参阅 Using Flow with Room (CodeLab) or Unidirectional data flow on Android using Kotlin(请参阅相关的 GitHub 存储库以获取大致相似的示例应用程序,该示例应用程序正在对其进行演示)。

如果您只在 class 中添加标题,房间将不会加载 body 我使用了以下依赖项

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
implementation 'androidx.room:room-runtime:2.2.4'
annotationProcessor 'androidx.room:room-compiler:2.2.4'

而我创建的SimpleNote class如下

public class SimpleNote {
    private String title;

    public SimpleNote(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }
}

我只能查询标题如下

@Dao
public interface NotesDao {
    @Query("SELECT * FROM notes_table")
    LiveData<List<Notes>> loadAllNotes();

    @Insert
    void insertNotes(List<Notes> notes);

    //loads only the title
    @Query("SELECT * FROM notes_table")
    LiveData<List<SimpleNote>> loadSimpleNotes();
}

"Returning subsets of columns" 文档中所示:

Most of the time, you need to get only a few fields of an entity. For example, your UI might display just a user's first name and last name, rather than every detail about the user. By fetching only the columns that appear in your app's UI, you save valuable resources, and your query completes more quickly.

Room allows you to return any Java-based object from your queries as long as the set of result columns can be mapped into the returned object. For example, you can create the following plain old Java-based object (POJO) to fetch the user's first name and last name:

data class NameTuple(
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)

Now, you can use this POJO in your query method:

@Dao
interface MyDao {
    @Query("SELECT first_name, last_name FROM user")
    fun loadFullName(): List<NameTuple>
}

Room understands that the query returns values for the first_name and last_name columns and that these values can be mapped into the fields of the NameTuple class. Therefore, Room can generate the proper code. If the query returns too many columns, or a column that doesn't exist in the NameTuple class, Room displays a warning.


回到你的案例:已经这样定义了 SimpleNote

public class SimpleNote {
    @ColumnInfo(name = "title")
    private String title;
}

然后可以查询table:

@Query("SELECT title FROM note")
public abstract LiveData<List<SimpleNote>> getAllSimpleNotes();

可以直接使用

@Query("SELECT title FROM note")
public abstract LiveData<List<SimpleNote>> getAllSimpleNotes();


public class SimpleNote {
    private String title;
}

只要您的列名称相同,即标题

您可以使用同样可扩展的 view into the database

@DatabaseView(value = "SELECT title FROM note", viewName = "simple-note")
public class SimpleNote {
    @ColumnInfo(name = "title")
    private String title;
}

您只需要在数据库实体中注册它。

@Database(entities = {Note.class}, views = {SimpleNote.class}, version = 3)

Note: Like entities, you can run SELECT statements against views. However, you cannot run INSERT, UPDATE, or DELETE statements against views.

@Query("SELECT * from simple-note")
public abstract LiveData<List<SimpleNote>> getAllSimpleNotes();

您可以return房间中的任何 POJO select 查询函数,您只需要在查询字符串中坚持使用 POJO 的字段名称即可。

class SumAveragePojo
{ 
    public float total;
    public float average;
}

如果您的查询return包含 POJo 的所有必需字段,那么您就可以开始了。这是灵活性的示例:

@Query("SELECT SUM(stepCount) as total, AVG(stepCount) as average FROM userFitnessDailyRecords where forDay BETWEEN :startDay AND :endDay ORDER BY forDay ASC")
SumAveragePojo getUserFitnessSumAndAverageForLastThirtyDays(Date startDay, Date endDay);

所以你可以安全地做:

@Query("SELECT title FROM note") 
LiveData<List<SimpleNote>> getAllNoteTitles();