有两张桌子的房间实体?

Posted

技术标签:

【中文标题】有两张桌子的房间实体?【英文标题】:Room entity with two tables? 【发布时间】:2021-10-02 17:07:59 【问题描述】:

是否可以用两张桌子创建房间实体?我知道存储重复数据不是最佳做法,但我需要一个备份表来将数据恢复到其原始状态。

@Entity(tableName = "models", "backupModels")
public class Entity 

    @PrimaryKey
    @ColumnInfo(name = "id")
    private int id;

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

    public Entity() 

    

    public int getId() 
        return id;
    

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

    public String getModel() 
        return model;
    

    public void setModel(String model) 
        this.model = model;
    

【问题讨论】:

将表合并为一个表(即将两个表中的所有列添加到一个表中),但是正如您所说,这违反了数据库的基本规则 我正在使用 Entity.class 从 Firestore 加载数据并在本地缓存数据,所以我不想在 Firestore 中有重复的字段,只有当我缓存数据时。 【参考方案1】:

是否可以用两张桌子创建房间实体?

没有,@Entity 只定义了一个表。

您可以只复制实体重命名类并使用另一组 Dao。

但是,如果它只是为了后面的目的,那么也许可以考虑以下工作示例(设计为只运行一次)。

这是基于CREATE TABLE ? AS SELECT statements 并用于恢复INSERT INTO table SELECT ...;

您只需要没有任何更改的单个实体(除了删除第二个表名)。 实体:-

@androidx.room.Entity(tableName = "models"/* can't do, "backupModels"*/)
public class Entity 

    @PrimaryKey
    @ColumnInfo(name = "id")
    private int id;

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

    public Entity() 

    

    public int getId() 
        return id;
    

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

    public String getModel() 
        return model;
    

    public void setModel(String model) 
        this.model = model;
    

一个非常基本的@Dao AllDao(允许演示):-

@Dao
abstract class AllDao 

    @Insert
    abstract long insert(Entity entity);

    @Query("SELECT * FROM models")
    abstract List<Entity> getAllModels();

备份/恢复代码在@Database TheDatabase 中编码:-

@Database(entities = Entity.class,version = 1)
abstract class TheDatabase extends RoomDatabase 
    abstract AllDao getAllDao();

    private static final String SUFFIX_BACKUP = "_backup", SUFFIX_OLD = "_old";

    private static volatile TheDatabase instance = null;

    public static TheDatabase getInstance(Context context) 
        if (instance == null) 
            instance = Room.databaseBuilder(context,TheDatabase.class,"my.db")
                    .allowMainThreadQueries()
                    .build();
        
        return instance;
    

    public static void backupTable(String table) 
        SupportSQLiteDatabase db = instance.getOpenHelper().getWritableDatabase();
        db.beginTransaction();
        db.execSQL("DROP TABLE IF EXISTS `" + table + SUFFIX_BACKUP + "`;");
        db.execSQL("CREATE TABLE `" + table + SUFFIX_BACKUP + "` AS SELECT * FROM `" + table + "`");
        db.setTransactionSuccessful();
        db.endTransaction();
    

    public static void restoreTable(String table) 
        SupportSQLiteDatabase db = instance.getOpenHelper().getWritableDatabase();
        db.beginTransaction();
        db.execSQL("DROP TABLE IF EXISTS `" + table + SUFFIX_OLD + "`");
        db.execSQL("CREATE TABLE `" + table + SUFFIX_OLD + "` AS SELECT * FROM `" + table +"`;");
        db.execSQL("DELETE FROM `" + table + "`;");
        db.execSQL("INSERT INTO `" + table + "` SELECT * FROM `" +table + SUFFIX_BACKUP + "`;");
        db.execSQL("DROP TABLE IF EXISTS `" + table + SUFFIX_OLD + "`;");
        db.setTransactionSuccessful();
        db.endTransaction();
    

注意restorebackup 方法可以满足任何表。但是,可能必须考虑遵守约束(例如,如果使用外键约束)。

restore 方法会创建进一步的备份(可选)作为以防万一的备份 (models_old)。 DROPping models_old 表是可选的。

将它们放在一起并进行演示是 MainActivity :-

public class MainActivity extends AppCompatActivity 

    TheDatabase db;
    AllDao dao;

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

        Entity e = new Entity();
        e.setId(1);
        e.setModel("Model1");
        dao.insert(e);
        TheDatabase.backupTable("models");
        e.setId(2);
        e.setModel("Model2");
        dao.insert(e);
        for(Entity entity: dao.getAllModels()) 
            Log.d("PRERESTORE","ID = " + entity.getId() + " Model = " + entity.getModel());
        
        TheDatabase.restoreTable("models");
        for(Entity entity: dao.getAllModels()) 
            Log.d("POSTRESTORE","ID = " + entity.getId() + " Model = " + entity.getModel());
        
    

所以这个:-

    向模型表添加 1 行。 进行备份。 向模型表添加第二行。 将模型表的内容写入日志(2 行)。 恢复模型表(到存在 1 行时)。 将恢复模型表的内容写入日志(1 行)。

结果

运行时日志包括:-

2021-07-27 07:41:11.991 D/PRERESTORE: ID = 1 Model = Model1
2021-07-27 07:41:11.992 D/PRERESTORE: ID = 2 Model = Model2


2021-07-27 07:41:11.996 D/POSTRESTORE: ID = 1 Model = Model1
注意 请注意使用CREATE TABLE ... AS SELECT ....时的限制

【讨论】:

以上是关于有两张桌子的房间实体?的主要内容,如果未能解决你的问题,请参考以下文章

使用实体框架6进入和编辑导航属性

实体框架代码优先:在具有不同连接列的实体中展平组合

实体框架不识别一对多关联。为啥?

使用 SQL 和 Linq 的多对多关系(实体框架/实体)

Hibernate:从一个到多个表中查找实体

外键上的实体框架nvarchar案例敏感性