Room Java - 是否可以在介面中執行事務?
P粉852578075
P粉852578075 2024-01-10 17:15:07
0
1
391

我在我的 Android Studio 專案中使用 room 框架。我正在嘗試在介面內建立事務。我已經從這裡閱讀了文件:https://developer.android.com/reference/androidx/room/Transaction

我知道我們應該在抽象類別中而不是在介面中建立事務。我只是想知道這是否可能,因為我的專案中已經有十多個接口,並且不想將它們重寫為抽象類別。

P粉852578075
P粉852578075

全部回覆(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 行):-

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!