Rumah  >  Soal Jawab  >  teks badan

Room Java - Adakah mungkin untuk menjalankan transaksi dalam antara muka?

Saya menggunakan rangka kerja bilik dalam projek Android Studio saya. Saya cuba membuat transaksi dalam antara muka. Saya telah membaca dokumentasi dari sini: https://developer.android.com/reference/androidx/room/Transaction

Saya tahu kita harus membuat transaksi dalam kelas abstrak dan bukannya antara muka. Saya hanya tertanya-tanya sama ada ini mungkin kerana saya sudah mempunyai lebih daripada sedozen antara muka dalam projek saya dan tidak mahu menulis semula mereka sebagai kelas abstrak.

P粉852578075P粉852578075283 hari yang lalu398

membalas semua(1)saya akan balas

  • P粉464208937

    P粉4642089372024-01-11 13:32:33

    Apa yang anda cuba lakukan tidak boleh dilakukan dalam antara muka kerana anda tidak boleh menggunakan kaedah dengan badan dalam antara muka.

    Secara lebih khusus, anda cuba melaksanakan berbilang kenyataan (KEMASKINI, kemudian PADAM), tetapi hanya satu kenyataan boleh dilaksanakan pada masa yang sama.

    Pilihan anda adalah untuk menentukan pencetus (dikemas kini jika baris berat boleh ditentukan dari dalam pencetus) atau mungkin lebih berkemungkinan menggunakan kelas abstrak dan dengan itu menggunakan fungsi untuk melaksanakan berbilang kenyataan atau menggunakan kaedah yang dieksploitasi (lulus/atau dapatkan semula )SupportSQliteDatabase (menggunakan kelas abstrak adalah lebih mudah).

    • Jika anda memerlukan pencetus, anda mesti menggunakan panggilan balik untuk membuat pencetus kerana Bilik tidak menyediakan anotasi pencetus.

    Kemudian, untuk memanfaatkan urus niaga, anda akan mempunyai dummy @Query sebelum fungsi. Contohnya

    @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();
        }
    }
    • NOTA - Kod pada asasnya ialah kod dan belum disusun, dijalankan atau diuji, jadi ia mungkin mengandungi beberapa pepijat

    Tambahan

    Ini adalah demo yang berfungsi, direka untuk dijalankan sekali sahaja, ia menggunakan ketiga-tiga kaedah.

    Pertama @Entities, berdasarkan apa yang tersedia dalam kod, tetapi sudah menggunakan panjang untuk mewakili tarikh (bukannya menggunakan penukar jenis).

    Lawati

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

    Berat

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

    @Dao Kelas abstrak beranotasi dengan kaedah dan kaedah abstrak biasa dengan badan (Penyelesaian 1). Kaedah sisipan membenarkan memasukkan beberapa data (hanya satu baris).

    @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();
        }
    }

    Kini, @Database kelas beranotasi (menggunakan bujang) sedikit lebih rumit.

    Ini mempunyai panggilan balik untuk menambah pencetus, pencetus adalah terlalu rumit kerana ia bukan sahaja memadamkan selepas kemas kini (tidak memadamkan apa-apa) tetapi juga menambah baris baharu dalam jadual akses yang menunjukkan bahawa TRIGGER sebenarnya sedang dicetuskan (penyelesaian 2) .

    Selain itu, untuk alasan yang lebih baik (atau tidak bergantung pada gaya/latihan), sertakan fungsi untuk mendapatkan dan menggunakan SupportSQLiteDatabase (penyelesaian 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);
            }
        };
    }

    Untuk benar-benar menggunakan beberapa kod aktiviti di atasMainActivity

    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
             */
        }
    }

    Hasil demo melalui SppInspection

    Seperti dijangka meja berat kosong :-

    Seperti yang dijangka, terdapat 4 baris dalam jadual akses:-

    Akhir sekali, skema (iaitu sqlite_master) menunjukkan bahawa pencetus wujud (terpaksa menambah 3 baris tambahan):-

    balas
    0
  • Batalbalas