You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Room持久化对象映射技术咨询——附Subject与Grade实体类代码

Room Persistence 对象映射技术详解(结合实体类实例)

Hey folks, let's dive deep into how object-relational mapping (ORM) works in Android's Room Persistence Library, using the two entity classes you provided as concrete examples. Room takes the pain out of raw SQLite by mapping your Java objects directly to database tables—so let's break down every annotation and its role in your code.

1. 基础实体映射:@Entity 注解

First up, the @Entity annotation marks a class as a database table. Every instance of this class will correspond to a row in the table.

Looking at your Subject.java:

@Entity(tableName = Constants.SUBJECT_ENTITY)
public class Subject {
    // ...
}
  • tableName: Explicitly sets the name of the database table. Using a constant (like Constants.SUBJECT_ENTITY) instead of a hardcoded string makes your code easier to maintain—if you ever need to rename the table, you only change it in one place.

Your Grade.java uses the same pattern, plus an extra foreignKeys parameter we'll cover next:

@Entity(tableName = Constants.GRADE_ENTITY, foreignKeys = @ForeignKey(...))
public class Grade implements Serializable {
    // ...
}

2. 主键定义:@PrimaryKey 注解

Every database table needs a primary key to uniquely identify rows—Room enforces this with the @PrimaryKey annotation.

In both your entities:

@PrimaryKey
private int id;
  • This maps the id field to the primary key column of the table.
  • Note: If you want SQLite to auto-generate unique IDs for new rows, add autoGenerate = true to the annotation: @PrimaryKey(autoGenerate = true). Your current code assumes you'll manually set the id value when creating instances.

3. 列名自定义:@ColumnInfo 注解

By default, Room uses the field name as the column name in the table. But if you want a different column name (for consistency with existing database schemas, or to avoid naming conflicts), use @ColumnInfo.

In Subject.java:

@ColumnInfo(name = "name")
private String name;

Here, the field name maps to a column named name (which matches, but it's still a good practice to use the annotation explicitly). For a more practical example, if your field was subjectName, you could use @ColumnInfo(name = "name") to map it to a shorter column name.

In Grade.java, you apply the same logic to the semester field:

@ColumnInfo(name = "semester")
private int semester;

4. 表关联:@ForeignKey 注解

This is where things get interesting—Room uses @ForeignKey to establish relationships between tables. Your Grade entity is linked to Subject because a grade belongs to a specific subject.

Let's unpack the @ForeignKey in your Grade.java:

foreignKeys = @ForeignKey(
        entity = Subject.class,
        onDelete = CASCADE,
        parentColumns = "id",
        childColumns = "subjectId"
)

Let's break down each parameter:

  • entity = Subject.class: Specifies the parent entity (the table we're linking to).
  • parentColumns = "id": The column in the parent table (Subject) that acts as the primary key for the relationship.
  • childColumns = "subjectId": The column in the child table (Grade) that stores the foreign key value (matching the id of a Subject). You'll need to add this field to your Grade class (I've included it in the full code snippet below).
  • onDelete = CASCADE: A critical constraint—this means if a Subject is deleted from the database, all linked Grade records will be automatically deleted too. This prevents "orphaned" grade entries that don't belong to any subject.

Here's the complete Grade class with the missing subjectId field:

@Entity(tableName = Constants.GRADE_ENTITY, foreignKeys = @ForeignKey(
        entity = Subject.class,
        onDelete = CASCADE,
        parentColumns = "id",
        childColumns = "subjectId"))
public class Grade implements Serializable {
    @PrimaryKey
    private int id;
    @ColumnInfo(name = "semester")
    private int semester;
    @ColumnInfo(name = "subjectId")
    private int subjectId; // Foreign key linking to Subject's id

    // Constructor, getters, and setters omitted for brevity
}

If you want to fetch a Subject along with all its associated Grade records in a single query, you can create a wrapper class with the @Relation annotation:

public class SubjectWithGrades {
    @Embedded // Embeds the Subject fields directly into the result
    private Subject subject;
    
    @Relation(
          parentColumn = "id",
          entityColumn = "subjectId"
    )
    private List<Grade> grades; // List of linked Grade records
}

You can then define a DAO method to query this:

@Query("SELECT * FROM subject")
List<SubjectWithGrades> getSubjectsWithGrades();

Key Takeaways

  • @Entity turns a class into a database table.
  • @PrimaryKey defines the unique identifier for rows.
  • @ColumnInfo lets you customize column names.
  • @ForeignKey establishes relationships between tables and enforces constraints like cascading deletes.
  • @Relation simplifies fetching related data in one go.

Hope this breakdown clarifies how Room maps your objects to database tables and handles relationships. Feel free to ask follow-up questions about DAOs, query optimization, or more advanced ORM features!

内容的提问来源于stack exchange,提问作者Kamil Grosicki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:28:28