繁体   English   中英

如何使用 Room 创建多个表?

[英]How can I create several tables, using Room?

我有一些问题。 在我的应用程序中,我使用名为“模板”的 Sqlite 数据库,我想创建几个表,例如peopleTemplatesanimalsTemplates ,它们由iddescriptionimage_link列组成。 还会有特殊的表格favourites ,我将添加所有用户喜欢的模板。 我将使用RoomDatabase 这是我的TemplatesClass

@Entity(tableName = "my_templates")
public class MyTemplate implements Serializable {

    @PrimaryKey(autoGenerate = true)
    public int id;

    @ColumnInfo(name = "description")
    public String titleTemplate;

    @ColumnInfo(name = "image_link")
    public String imageLink;

    public String getTitleTemplate() {
        return titleTemplate;
    }

    public void setTitleTemplate(String titleTemplate) {
        this.titleTemplate = titleTemplate;
    }

    public String getImageLink() {
        return imageLink;
    }

    public void setDrawableID(String imageLink) {
        this.imageLink = imageLink;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }


    public MyTemplate(String titleTemplate, String imageLink){
        this.titleTemplate = titleTemplate;
        this.imageLink = imageLink;
    }

    public MyTemplate(){}
}

我的数据库类:


@Database(entities = {MyTemplate.class}, version = 1, exportSchema = false)
public abstract class RoomDB extends RoomDatabase {
   private static RoomDB database;

   private final static String DATABASE_NAME = "Templates";

   public synchronized static RoomDB getInstance(Context context){
       if(database == null){
           database = Room.databaseBuilder(context.getApplicationContext(),
                   RoomDB.class, DATABASE_NAME)
                   .allowMainThreadQueries()
                   .fallbackToDestructiveMigration()
                   .build();
       }
       return  database;
   }

   public abstract TemplateDao templateDao();
}

还有我的道:


@Dao
public interface TemplateDao {
    @Insert(onConflict = REPLACE)
    void insert(MyTemplate myTemplate);

    @Delete
    void delete(MyTemplate myTemplate);

    @Delete
    void reset(ArrayList<MyTemplate> myTemplates);

    @Query("UPDATE my_templates SET description = :sDescription WHERE id = :sID")
    void update(int sID, String sDescription);

    @Query("SELECT * FROM my_templates")
    List<MyTemplate> getAll();
}

  1. 使用@Entity为其他表创建实体。

  2. 创建适当的道(您选择的每个实体都在一个或一个)

  3. 修改 @Database(RoomDB 类) entities =以将其他实体类包含在实体数组中。 如果使用多个 Dao,则添加用于检索 Dao 的抽象方法(即类似于public abstract TemplateDao templateDao(); )。

至少对于模板表来说,如果您添加了一个表示类型(人、动物等)的列,那么一个表就足以满足所有模板的需求

示例 1 - 附加表

1.创建新实体

@Entity(tableName = "people_templates")
public class PeopleTemplate implements Serializable {

    @PrimaryKey(autoGenerate = true)
    public long id; //<<<<<<<<< Should really be long not int

    @ColumnInfo(name = "description")
    public String titleTemplate;

    @ColumnInfo(name = "image_link")
    public String imageLink;

    public String getTitleTemplate() {
        return titleTemplate;
    }

    public void setTitleTemplate(String titleTemplate) {
        this.titleTemplate = titleTemplate;
    }

    public String getImageLink() {
        return imageLink;
    }

    public void setDrawableID(String imageLink) {
        this.imageLink = imageLink;
    }

    public long getId() { // long
        return id;
    }

    public void setId(long id) { // long
        this.id = id;
    }

    public PeopleTemplate(String titleTemplate, String imageLink){
        this.titleTemplate = titleTemplate;
        this.imageLink = imageLink;
    }

    public PeopleTemplate(){}
}
  • 请注意,对于 id 列,int 已更改为 long。 理论上 id 可以很长,Room 在使用 @Insert 时期望返回 long。

2.修改道

@Dao
public interface TemplateDao {
    @Insert(onConflict = REPLACE)
    void insert(MyTemplate myTemplate);
    @Insert(onConflict = REPLACE)
    long insert(PeopleTemplate peopleTemplate); // long will hold the id of the inserted row
    @Insert(onConflict = REPLACE)
    long[] insert(PeopleTemplate...peopleTemplates); // allows many (e.g. ArrayList to be added), returns long[] of id's inserted

    @Delete
    void delete(MyTemplate myTemplate);
    @Delete
    int delete(PeopleTemplate...peopleTemplate); // delete 1 or many, returns number deleted
    @Delete
    void reset(ArrayList<MyTemplate> myTemplates);

    @Query("UPDATE my_templates SET description = :sDescription WHERE id = :sID")
    void update(int sID, String sDescription);
    @Query("UPDATE people_templates SET description = :sDescription WHERE id = :sID")
    int update(long sID, String sDescription); // returns number of updates

    @Query("SELECT * FROM my_templates")
    List<MyTemplate> getAll();
    @Query("SELECT * FROM people_templates")
    List<PeopleTemplate> getAllPeopleTemplates();
}
  • 注释注释

3.并入@Database class

//@Database(entities = {MyTemplate.class}, version = 1, exportSchema = false) <<<<<<<<<< WAS THIS
@Database(entities = {MyTemplate.class,PeopleTemplate.class}, version = 1, exportSchema = false) //<<<<<<<<<< CHANGED
public abstract class RoomDB extends RoomDatabase {
    private static RoomDB database;

    private final static String DATABASE_NAME = "Templates";

    public synchronized static RoomDB getInstance(Context context){
        if(database == null){
            database = Room.databaseBuilder(context.getApplicationContext(),
                    RoomDB.class, DATABASE_NAME)
                    .allowMainThreadQueries()
                    .fallbackToDestructiveMigration()
                    .build();
        }
        return  database;
    }

    public abstract TemplateDao templateDao();
}

示例 2 - 单表

这是一个适用于多种模板类型的单个模板表的工作示例

单一模板实体

@Entity(tableName = "templates")
public class SingleTemplate implements Serializable {

    public static final int MY_TEMPLATE = 0;
    public static final int PEOPLE_TEMPLATE = 1;
    public static final int ANIMAL_TEMPLATE = 2;

    /* suggest not using AUTOGENERATE as it has overheads
        using Long and passing null has the same result without overheads
     */
    @PrimaryKey
    Long id;
    @ColumnInfo(name = "description")
    String title;
    @ColumnInfo(name = "image_link")
    String imageLink;
    @ColumnInfo(name = "template_type")
    int templateType;

    public SingleTemplate(){}

    // Use @Ignore to suppress warning "There are multiple good constructors and Room will pick the no-arg constructor...."
    @Ignore
    public SingleTemplate(String title, String imageLink, int templateType) {
        this.title = title;
        this.imageLink = imageLink;
        this.templateType = templateType;
    }

    /* Method to allow conversion of type to a user readable String */
    public static String getType(int templateType) {
        switch (templateType) {
            case MY_TEMPLATE:
                return "MY";
            case PEOPLE_TEMPLATE:
                return "PEOPLE";
            case ANIMAL_TEMPLATE:
                return "ANIMAL";
            default:
                return "UNKNOWN";
        }
    }
}

The Dao SingleTemplateDao

@Dao
interface SingleTemplateDao {

    @Insert(onConflict = REPLACE)
    long insert(SingleTemplate singleTemplate);
    @Insert(onConflict = REPLACE)
    long[] insert(SingleTemplate...singleTemplates);
    @Update
    int update(SingleTemplate...singleTemplate);
    @Query("SELECT * FROM templates WHERE template_type IN (:arrayOfTypes)")
    List<SingleTemplate> getTemplatesByTypes(int[] arrayOfTypes);
}

@Database class RoomDBSingleTemplate

@Database(entities = {SingleTemplate.class}, version = 1, exportSchema = false) //<<<<<<<<<< CHANGED
public abstract class RoomDBSingleTemplate extends RoomDatabase {
    private static RoomDBSingleTemplate database;

    private final static String DATABASE_NAME = "Templates";

    public synchronized static RoomDBSingleTemplate getInstance(Context context){
        if(database == null){
            database = Room.databaseBuilder(context.getApplicationContext(),
                    RoomDBSingleTemplate.class, DATABASE_NAME)
                    .allowMainThreadQueries()
                    .fallbackToDestructiveMigration()
                    .build();
        }
        return  database;
    }

    public abstract SingleTemplateDao getSingleTemplateDao();
}

MainActivity中的调用/演示代码

public class MainActivity extends AppCompatActivity {

    RoomDBSingleTemplate db;
    SingleTemplateDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        db = RoomDBSingleTemplate.getInstance(this);
        dao = db.getSingleTemplateDao();

        // Add one of each type individually
        long id = dao.insert(new SingleTemplate("Template1","Link1",SingleTemplate.MY_TEMPLATE));
        dao.insert(new SingleTemplate("Template2","Link2", ANIMAL_TEMPLATE));
        dao.insert(new SingleTemplate("Template3","Link3",SingleTemplate.PEOPLE_TEMPLATE));
        // Add an unknown type
        dao.insert(new SingleTemplate("Template4","LINK4",99999));

        // Add many templates type determined according to iteration
        int limit = 10;
        SingleTemplate[] stList = new SingleTemplate[limit];
        for(int i=0; i < limit; i++) {
            stList[i] = new SingleTemplate(
                    "Template" + (i+100),
                    "Link" + (i+100),
                    i % 3
            );
        }
        dao.insert(stList);

        // Get just Animal templates and update the Link by prefixing with ANIMAL
        List<SingleTemplate> animalTemplates =  dao.getTemplatesByTypes(new int[]{ANIMAL_TEMPLATE});
        stList = new SingleTemplate[animalTemplates.size()];
        int i=0;
        for (SingleTemplate s: animalTemplates) {
            s.imageLink = "ANIMAL" + s.imageLink;
            stList[i++] = s;
        }
        dao.update(stList);

        // Get all known types and output to the log
        List<SingleTemplate> allTemplates = dao.getTemplatesByTypes(new int[]{MY_TEMPLATE,ANIMAL_TEMPLATE,PEOPLE_TEMPLATE});
        for(SingleTemplate s: allTemplates) {
            Log.d("TEMPLATEINFO",
                    "Title is " + s.title +
                            " Link is " + s.imageLink +
                            " Type is " + SingleTemplate.getType(s.templateType) +
                            " ID is " + s.id
            );
        }
    }
}

结果- 日志中的 Output。

2021-06-09 07:44:18.163 D/TEMPLATEINFO: Title is Template1 Link is Link1 Type is MY ID is 1
2021-06-09 07:44:18.163 D/TEMPLATEINFO: Title is Template2 Link is ANIMALLink2 Type is ANIMAL ID is 2
2021-06-09 07:44:18.163 D/TEMPLATEINFO: Title is Template3 Link is Link3 Type is PEOPLE ID is 3
2021-06-09 07:44:18.163 D/TEMPLATEINFO: Title is Template100 Link is Link100 Type is MY ID is 5
2021-06-09 07:44:18.163 D/TEMPLATEINFO: Title is Template101 Link is Link101 Type is PEOPLE ID is 6
2021-06-09 07:44:18.164 D/TEMPLATEINFO: Title is Template102 Link is ANIMALLink102 Type is ANIMAL ID is 7
2021-06-09 07:44:18.164 D/TEMPLATEINFO: Title is Template103 Link is Link103 Type is MY ID is 8
2021-06-09 07:44:18.164 D/TEMPLATEINFO: Title is Template104 Link is Link104 Type is PEOPLE ID is 9
2021-06-09 07:44:18.164 D/TEMPLATEINFO: Title is Template105 Link is ANIMALLink105 Type is ANIMAL ID is 10
2021-06-09 07:44:18.164 D/TEMPLATEINFO: Title is Template106 Link is Link106 Type is MY ID is 11
2021-06-09 07:44:18.164 D/TEMPLATEINFO: Title is Template107 Link is Link107 Type is PEOPLE ID is 12
2021-06-09 07:44:18.164 D/TEMPLATEINFO: Title is Template108 Link is ANIMALLink108 Type is ANIMAL ID is 13
2021-06-09 07:44:18.164 D/TEMPLATEINFO: Title is Template109 Link is Link109 Type is MY ID is 14

可以看出

  • 已添加 14 行(最后一个 ID 为 14)
  • 所有具有 ANIMAL 类型的行都更新了链接
  • 已从 output 中省略了 UNKNOWN 行(ID 为 4 的模板 4)

更进一步

你说:-

还会有特别的表收藏夹,我将在那里添加用户喜欢的所有模板。 我将使用 RoomDatabase。

假设用户有多个用户(如果只有 1 个用户则不会受到伤害,尽管如果只有 1 个用户则不需要那么复杂)。

你可能有一个用户表,例如:-

@Entity(tableName = "user")
public class User {

    @PrimaryKey
    Long id;
    String userName;
    String userEmail;
    String userPassword;

    public User(){};

    @Ignore
    public User(String userName, String userEmail, String userPassword) {
        this.userName = userName;
        this.userEmail = userEmail;
        this.userPassword = userPassword;
    }
}

要将用户与他们最喜欢的模板链接并允许用户使用其他用户使用的模板,则需要多对多关系。 因此,收藏夹表可能是用户和他们喜欢的模板之间的 map。 对于 map,您所需要的只是用户的唯一标识符以及模板的唯一标识符(例如每个 id 列)。 因此,收藏夹表可以是:-

/*
    Mapping Table for many-many relationship between users and templates
 */
@Entity(
        tableName = "favourite",
        foreignKeys = {
                @ForeignKey(
                        entity = User.class,
                        parentColumns = {"id"},
                        childColumns = {"userId"},
                        onDelete = CASCADE,
                        onUpdate = CASCADE
                        ),
                @ForeignKey(
                        entity = SingleTemplate.class,
                        parentColumns = {"id"},
                        childColumns = {"templateId"},
                        onDelete = CASCADE,
                        onUpdate = CASCADE
                        )
        },
        /* composite Primary Key */
        primaryKeys = {"userId","templateId"},
        indices = {@Index("templateId")}
)
public class Favourites {

    long userId;
    long templateId;

    public Favourites(){}

    @Ignore
    public Favourites(long userId,long templateId) {
        this.userId = userId;
        this.templateId = templateId;
    }
}
  • 这种表有很多术语,例如关联表、引用表、映射表......
  • ForeignKey 定义定义了管理/断言引用完整性的规则,它们不是必需的,但它们可能会有所帮助
    • 他们可以防止孤儿被添加。 也就是说,如果尝试添加列值在相应父项中不存在的行,则会发生外键冲突(参见 Dao)。
    • onDelete = CASCADE 将级联删除父级,以便删除子级中引用父级的所有行。
    • onUpdate 类似,但它只会导致子项中的引用列发生更改,并且仅当引用列发生更改时(这种情况很少发生)。
  • 有两个 ForeignKey 定义,一个用于对 User 表的引用/关系,另一个用于对 SingleTemplates 表的引用/关系。
  • templateId 列上的索引不是必需的,但如果省略 Room 会发出警告。

在这个阶段,可以添加用于插入和检索用户和收藏夹的 Dao。 但是,检索收藏夹并不是那么用户友好,它们只是没有意义的数字。 例如

  • 1,13 真的意味着 id 为 1 的用户有一个指向 id 为 13 的模板的链接......

因此,您可能希望获取用户详细信息以及模板详细信息。 Room 让这很容易你创建一个POJO class (不是实体),在其中嵌入一个实体,然后定义与另一个 class 的关系(嵌入用户模板的关系) 但是,由于映射表位于两者之间(仅 Embed 和 Relation 满足一对多关系) ,因此您需要一个定义三个表之间的连接关联

因此,合适的 POJO 可能是UserWithFavourites :-

public class UserWithFavourites {

    @Embedded
    User user; /* One User */
    @Relation(entity = SingleTemplate.class, parentColumn = "id",entityColumn = "id",
    associateBy = @Junction(value = Favourites.class,parentColumn = "userId",entityColumn = "templateId"))
    List<SingleTemplate> singleTemplateList; /* A list of Templates for the User */
}

所以需要一个 Dao 来检索(查询)数据库。 所以SingleTemplateDao现在可以是:-

@Dao
interface SingleTemplateDao {

    @Insert(onConflict = REPLACE)
    long insert(SingleTemplate singleTemplate);
    @Insert(onConflict = REPLACE)
    long[] insert(SingleTemplate...singleTemplates);
    @Insert(onConflict = REPLACE)
    long[] insert(User...users);
    @Insert(onConflict = IGNORE)
    long[] insert(Favourites...favourites);
    @Update
    int update(SingleTemplate...singleTemplate);
    @Query("SELECT * FROM templates WHERE template_type IN (:arrayOfTypes)")
    List<SingleTemplate> getTemplatesByTypes(int[] arrayOfTypes);
    @Query("SELECT * FROM user")
    List<User> getAllUsers();
    @Query("SELECT * FROM user WHERE id=:userId")
    User getUserById(long userId);
    @Query("SELECT * FROM User")
    List<UserWithFavourites> getAllUsersWithFavourites();

}

示例 3

  • 请注意,上面用于插入/更新和提取的代码已移至名为 example2 的方法。 创建了一个新方法 example3 来演示添加用户和收藏夹表,因此活动代码现在是:-

    公共 class MainActivity 扩展 AppCompatActivity {

     RoomDBSingleTemplate db; SingleTemplateDao dao; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); db = RoomDBSingleTemplate.getInstance(this); dao = db.getSingleTemplateDao(); example2(); example3(); } private void example3() { /* Add some Users */ dao.insert(new User("Fred","Fred@email.com","password"), /*ID will be 1 */ new User("Mary","Mary@email.com","password"), /* ID will be 2 */ new User("Sarah","Sarah@email.com","password") /* ID will be 3 */); /* Using the existing templates map/associate/relate users to templates */ dao.insert(new Favourites(1,1), new Favourites(1,3), new Favourites(1,4) /* UNKNOWN TYPE */, new Favourites(1,10), new Favourites(2,5), new Favourites(2,6), new Favourites(2,7), new Favourites(2,8), new Favourites(3,9), new Favourites(3,11), new Favourites(3,12), new Favourites(3,13), new Favourites(3,14)); /* extract all users with thier templates and then output the results to the log */ List<UserWithFavourites> userWithFavourites = dao.getAllUsersWithFavourites(); for (UserWithFavourites uwf: userWithFavourites) { Log.d("FAVOURITESINFO", "User is " + uwf.user.userName + " email is " + uwf.user.userEmail + " password is " + uwf.user.userPassword + " USERID = " + uwf.user.id + " # of Templates = " + uwf.singleTemplateList.size() ); for (SingleTemplate st: uwf.singleTemplateList) { Log.d("FAVOURITESINFO","Template is " + st.title + " Link is " + st.imageLink + " Type is " + getType(st.templateType) + " ID is " + st.id); } } } private void example2() { // Add one of each type individually long id = dao.insert(new SingleTemplate("Template1","Link1",SingleTemplate.MY_TEMPLATE)); dao.insert(new SingleTemplate("Template2","Link2", ANIMAL_TEMPLATE)); dao.insert(new SingleTemplate("Template3","Link3",SingleTemplate.PEOPLE_TEMPLATE)); // Add an unknown type dao.insert(new SingleTemplate("Template4","LINK4",99999)); // Add many templates type determined according to iteration int limit = 10; SingleTemplate[] stList = new SingleTemplate[limit]; for(int i=0; i < limit; i++) { stList[i] = new SingleTemplate( "Template" + (i+100), "Link" + (i+100), i % 3 ); } dao.insert(stList); // Get just Animal templates and update the Link by prefixing with ANIMAL List<SingleTemplate> animalTemplates = dao.getTemplatesByTypes(new int[]{ANIMAL_TEMPLATE}); stList = new SingleTemplate[animalTemplates.size()]; int i=0; for (SingleTemplate s: animalTemplates) { s.imageLink = "ANIMAL" + s.imageLink; stList[i++] = s; } dao.update(stList); // Get all known types and output to the log List<SingleTemplate> allTemplates = dao.getTemplatesByTypes(new int[]{MY_TEMPLATE,ANIMAL_TEMPLATE,PEOPLE_TEMPLATE}); for(SingleTemplate s: allTemplates) { Log.d("TEMPLATEINFO", "Title is " + s.title + " Link is " + s.imageLink + " Type is " + SingleTemplate.getType(s.templateType) + " ID is " + s.id ); } }

    }

示例 3 结果运行(第一次)时,日志包括:-

2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template1 Link is Link1 Type is MY ID is 1
2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template3 Link is Link3 Type is PEOPLE ID is 3
2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template4 Link is LINK4 Type is UNKNOWN ID is 4
2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template105 Link is ANIMALANIMALLink105 Type is ANIMAL ID is 10
2021-06-09 11:50:11.477 D/FAVOURITESINFO: User is Mary email is Mary@email.com password is password USERID = 2 # of Templates = 4
2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template100 Link is Link100 Type is MY ID is 5
2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template101 Link is Link101 Type is PEOPLE ID is 6
2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template102 Link is ANIMALANIMALLink102 Type is ANIMAL ID is 7
2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template103 Link is Link103 Type is MY ID is 8
2021-06-09 11:50:11.477 D/FAVOURITESINFO: User is Sarah email is Sarah@email.com password is password USERID = 3 # of Templates = 5
2021-06-09 11:50:11.477 D/FAVOURITESINFO: Template is Template104 Link is Link104 Type is PEOPLE ID is 9
2021-06-09 11:50:11.478 D/FAVOURITESINFO: Template is Template106 Link is Link106 Type is MY ID is 11
2021-06-09 11:50:11.478 D/FAVOURITESINFO: Template is Template107 Link is Link107 Type is PEOPLE ID is 12
2021-06-09 11:50:11.478 D/FAVOURITESINFO: Template is Template108 Link is ANIMALANIMALLink108 Type is ANIMAL ID is 13
2021-06-09 11:50:11.478 D/FAVOURITESINFO: Template is Template109 Link is Link109 Type is MY ID is 14

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM