Room Java – Ist es möglich, Transaktionen in der Schnittstelle auszuführen?
P粉852578075
P粉852578075 2024-01-10 17:15:07
0
1
439

Ich verwende das Room Framework in meinem Android Studio-Projekt. Ich versuche, eine Transaktion innerhalb einer Schnittstelle zu erstellen. Ich habe die Dokumentation hier gelesen: https://developer.android.com/reference/androidx/room/Transaction

Ich weiß, wir sollten Transaktionen in abstrakten Klassen statt in Schnittstellen erstellen. Ich frage mich nur, ob das möglich ist, da ich in meinem Projekt bereits mehr als ein Dutzend Schnittstellen habe und diese nicht als abstrakte Klassen umschreiben möchte.

P粉852578075
P粉852578075

Antworte allen(1)
P粉464208937

您所尝试的操作在接口中是不可能的,因为您不能在接口中使用带有主体的方法。

更具体地说,您尝试执行多个语句(一条 UPDATE,然后一条 DELETE),但同时只能执行一条语句。

您的选择是定义一个触发器(更新后,如果可以从触发器内确定权重行)或者可能更可能使用抽象类,从而使用一个函数来执行多个语句或使用利用的方法(传递/或检索)SupportSQliteDatabase(使用抽象类更简单)。

  • 如果您需要触发器,则必须使用回调来创建触发器,因为 Room 不提供触发器注释。

然后,要利用事务,您将在函数之前有一个虚拟的@Query。例如

@Dao
abstract class TheClassForMethodsWithBodies {

    @Query("UPDATE visits SET date=:date WHERE id=5")
    void testUpdate(Date date);
    @Query("DELETE FROM wieght WHERE id_weight=1")
    void testDelete();

    @Query("")
    void test(Date date) {
        testUpdate(date);
        testDelete();
    }
}
  • 注意 - 代码本质上是代码,尚未编译、运行或测试,因此可能包含一些错误

附加

这是一个工作演示,设计为仅运行一次,它使用所有三种方法。

首先是@Entities,基于代码中可用的内容,但已使用 long 来表示日期(而不是使用类型转换器)。

访问

@Entity
class Visits {
   @PrimaryKey
   Long id=null;
   Long date = System.currentTimeMillis() / 1000;
}

重量

@Entity
class Weight {
    @PrimaryKey
    Long id_weight=null;
}

@Dao 带注释的抽象类,具有普通的抽象方法和带主体的方法(解决方案 1)。 insert 方法允许插入一些数据(仅一行)。

@Dao
abstract class AllDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    abstract long insert(Visits visits);

    @Query("UPDATE visits SET date=:date WHERE id=1")
    abstract void resetVisitData(long date);
    @Query("DELETE FROM weight WHERE id_weight=5")
    abstract void deleteFromWeight();
    @Query("")
    void doBoth(long date) {
        resetVisitData(date);
        deleteFromWeight();
    }
}

现在,@Database 带注释的类(使用单例)稍微复杂一些。

这有一个回调来添加触发器,触发器过于复杂,因为它不仅在更新后进行删除(不是删除任何内容),而且还在访问表中添加一个新行显示 TRIGGER 实际上正在被触发(解决方案 2)。

此外,由于需要更好的地方(或不取决于风格/实践),包含一个函数来获取和使用 SupportSQLiteDatabase(解决方案 3)

@Database(entities = {Weight.class,Visits.class}, version = 1,exportSchema = false)
abstract class TheDatabase extends RoomDatabase {
    abstract AllDao getAllDao();

    private static TheDatabase INSTANCE;
    static TheDatabase getINSTANCE(Context context) {
        if (INSTANCE==null) {
            INSTANCE = Room.databaseBuilder(
                            context,
                            TheDatabase.class,
                            "the_database.db"
                    )
                    .allowMainThreadQueries()
                    .addCallback(cb)
                    .build();
        }
        return INSTANCE;
    }

    /* Solution 2 - via SupportSQLiteDatabase */
    void viaSupportSB(long date) {
        SupportSQLiteDatabase db = this.getOpenHelper().getWritableDatabase();
        db.beginTransaction();
        db.execSQL("UPDATE visits SET date=? WHERE id=1",new String[]{String.valueOf(date)});
        db.execSQL("DELETE FROM weight WHERE id_weight=-600");
        db.setTransactionSuccessful();
        db.endTransaction();
    }


    /* USING a TRIGGER (not intended to make sense/do anything useful just demo) */
    private static final String CREATETRIGGERSQL = "CREATE TRIGGER IF NOT EXISTS theTrigger AFTER UPDATE ON visits BEGIN DELETE FROM weight WHERE id_weight=5; INSERT OR IGNORE INTO visits (date) VALUES(strftime('%s','now')); END";
    static Callback cb  = new Callback() {
        @Override
        public void onCreate(@NonNull SupportSQLiteDatabase db) {
            super.onCreate(db);
            db.execSQL(CREATETRIGGERSQL);
        }

        @Override
        public void onDestructiveMigration(@NonNull SupportSQLiteDatabase db) {
            super.onDestructiveMigration(db);
        }

        @Override
        public void onOpen(@NonNull SupportSQLiteDatabase db) {
            super.onOpen(db);
            db.execSQL(CREATETRIGGERSQL);
        }
    };
}

要实际利用上面的一些活动代码MainActivity

public class MainActivity extends AppCompatActivity {

    TheDatabase roomInstance;
    AllDao dao;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        roomInstance = TheDatabase.getINSTANCE(this);
        dao = roomInstance.getAllDao();

        dao.insert(new Visits()); /* Insert a row */

        /* Solution 2 - via Trigger */
        dao.resetVisitData(System.currentTimeMillis() - (24 * 60 * 60 * 7 /* one week ago BUT OOOPS not divided by 1000 */));
        /* Solution 1 - via abstract class aka method with body */
        dao.doBoth(System.currentTimeMillis() / 1000);
        /* Solution 3 - via SupportSQLiteDatabase */
        roomInstance.viaSupportSB(System.currentTimeMillis() + (24 * 60 * 60 * 7 /*week in the future  again OOOPS not divided by 1000*/));
        
        /* Expected result
            1. sinlge row inserted into visits
            2. trigger adds another row into visits (row 2)
            3. doBoth updates so another row added to visits (row 3)
            4. via SupportSQLiteDatabase updates so another row added to visits (row 4)
            
            So 4 rows in visits no rows in weight
         */
    }
}

演示结果 通过 SppInspection

正如预期的重量表是空的:-

正如预期的那样,访问表中有 4 行:-

最后,架构(即 sqlite_master)显示触发器存在(必须添加额外的 3 行):-

Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage