Raum aktualisieren (oder einfügen, falls nicht vorhanden) Zeilen und Anzahl geänderter Zeilen zurückgeben

Lesezeit: 6 Minuten

Benutzer-Avatar
ip696

Ich brauche ein Update und wenn nicht vorhanden, füge eine Zeile in ROOM DB ein.

Ich mache das: productRepository.updateProducts(productsResponse.getProductItems());

Und:

@Override
public void updateProducts(final List<ProductItem> products) {
    new Thread(() -> {
        for (ProductItem item : products) {
            Product product = createProduct(item);
            productDao.insert(product);
        }
    }).start();
}

Und im DAO:

@Insert
void insert(Product products);

Aber ich habe Methode

@Update
void update(Product product);

Und ich habe einige Fragen:

  1. beide Methoden sind nichtig. Wie kann ich gespeicherte Produkte oder boolesche Flags oder eingefügte Zählwerte nach dem Einfügen zurückgeben?

  2. wenn ich versuche anzurufen update und ich habe keine Zeile, wird sie eingefügt?

  3. Wie kann ich die Zeile aktualisieren (wenn nicht – einfügen) und die Anzahl der aktualisierten oder eingefügten Zeilen zurückgeben?

  • Sie suchen nach UPSERT, das bereits hier gelöst ist stackoverflow.com/a/50736568/10516463

    – D-Fieber

    13. Januar 2021 um 13:21 Uhr


Benutzer-Avatar
Regenmacher

Wie @Danail Alexiev sagte @Insert kann zurückgeben a long. @Update kann ein zurückgeben int.

Aber zu welchem ​​Zweck verwenden Sie Update? Wenn Sie nur möchten, dass das gesamte Objekt durch das neue ersetzt wird, geben Sie einfach die an OnConflictStrategy

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Product products);

Das Ergebnis wird sein: nicht vorhandene Elemente werden hinzugefügt, bereits vorhandene Elemente werden durch die neuen ersetzt.

Im Bedarfsfall aktualisiere nur einen Parameter (wie Menge zum Beispiel) können Sie so etwas tun

  @Insert(onConflict = OnConflictStrategy.REPLACE)
  void insert(Product products);

  @Query("SELECT * from item WHERE id= :id")
  List<Product> getItemById(int id);

  @Query("UPDATE item SET quantity = quantity + 1 WHERE id = :id")
  void updateQuantity(int id)

  void insertOrUpdate(Product item) {
                List<Product> itemsFromDB = getItemById(item.getId())
                if (itemsFromDB.isEmpty())
                    insert(item)
                else
                    updateQuantity(item.getId())   
            }
        }

Das Ergebnis wird sein: Versuchen Sie, das Element in der Datenbank nachzuschlagen, wenn Sie es finden, aktualisieren Sie eine Eigenschaft, wenn nicht, fügen Sie einfach ein neues Element ein. Sie müssen also nur eine Methode aufrufen insertOrUpdate von Ihrem DAO.

  • Du bist der Lebensretter, Kumpel …. Ich wollte gerade ROOM Db hassen … Vielen Dank.

    – Kamran Ali

    11. April 2020 um 19:37 Uhr


  • Es gibt einige Probleme mit Rückgabetypen im obigen Code. Wenn kein Datensatz für die Abfrage vorhanden ist, sollte die Liste außerdem leer und nicht null zurückgeben.

    – tahsinRupam

    13. April 2020 um 7:24 Uhr

  • @Rainmaker freut mich 🙂

    – tahsinRupam

    13. April 2020 um 15:26 Uhr

  • Um dies weiter zu optimieren, können wir die Anzahl der in DB durchgeführten Transaktionen speichern, indem wir ConflictStrategy direkt als Ignore einfügen und den Rückgabetyp überprüfen. Wenn das Einfügen fehlschlägt, da der Datensatz vorhanden ist, wird der Datensatz direkt aktualisiert, andernfalls erfolgreich eingefügt. Dadurch entfällt das zusätzliche Suchen nach dem Datensatz in der DB.

    – Aschwini

    23. Juli 2020 um 13:07 Uhr


  • Seien Sie bei diesem Ansatz vorsichtig, da ConflictStrategy.REPLACE wie DELETE+INSERT funktioniert. Das bedeutet, dass alle Entitäten, die sich auf Fremdschlüssel in anderen Tabellen beziehen, gelöscht werden 🤦‍♂️

    – Pavel Shorochov

    9. August um 1:31

  1. Eine Methode, kommentiert mit @Insert kann zurückgeben a long. Dies ist die neu generierte ID für die eingefügte Zeile. Eine Methode, kommentiert mit @Update kann ein zurückgeben int. Dies ist die Anzahl der aktualisierten Zeilen.

  2. update versucht, alle Ihre Felder mit dem Wert des Primärschlüssels in a zu aktualisieren where Klausel. Wenn Ihre Entität noch nicht in der Datenbank gespeichert ist, wird die update Abfrage kann keine Zeile finden und aktualisiert nichts.

  3. Sie können verwenden @Insert(onConflict = OnConflictStrategy.REPLACE). Dadurch wird versucht, die Entität einzufügen, und wenn es eine vorhandene Zeile mit demselben ID-Wert gibt, wird sie gelöscht und durch die Entität ersetzt, die Sie einfügen möchten. Beachten Sie, dass bei Verwendung automatisch generierter IDs die resultierende Zeile eine andere ID hat als das Original, das ersetzt wurde. Wenn Sie die ID beibehalten möchten, müssen Sie sich eine benutzerdefinierte Methode dafür einfallen lassen.

  • Das ist keine gute Lösung. Es führt keine Einfügung oder Aktualisierung durch. Dies ist ein Ersatz, damit Sie Felder verlieren, die Sie nicht für das Update angegeben haben.

    – Salela

    4. Dezember 2018 um 0:18 Uhr

  • Der TL;DR-Sqlite-Ersetzungsvorgang könnte gegen onDelete-ForeignKey-Einschränkungen verstoßen, update jedoch nicht. Dies gilt nicht für den Anwendungsfall insertOrUpdate(), wenn Sie ersetzen, wenn Sie den Primärschlüssel in der Tabelle finden, wird die Zeile gelöscht, sodass eine Verletzung des Fremdschlüssels vermutet werden könnte, dass ein Update OnCascade behandeln könnte.

    – Marcos E.

    11. Januar 2019 um 10:46 Uhr


Sie können Ihre Datenbank überprüfen, ob es bereits Artikel mit einem bestimmten Feld gibt, zum Beispiel:

@Query("SELECT id FROM items WHERE id = :id LIMIT 1")
fun getItemId(id: String): String?

@Insert
fun insert(item: Item): Long

@Update(onConflict = OnConflictStrategy.REPLACE)
fun update(item: Item): Int

Item ist Ihr Objekt und in Ihrem Code:

 fun insertOrUpdate(item: Item) {
            database.runInTransaction {
                val id = getItemDao().getItemId(item.id)

                if(id == null)
                    getItemDao().insert(item)
                else
                    getItemDao().update(item)
            }
        }

  • Müssen Sie das DAO jedes Mal neu abrufen?

    – Tobiq

    6. April 2019 um 0:39 Uhr

  • Nur eine Semantik, aber sollte das nicht besser sein ItemDao statt getItemDao?

    – Hiro

    17. Dezember 2020 um 9:24 Uhr

Sie können die folgende Methode insertModel() überprüfen, wo Sie die Methoden onComplete() und onError() abrufen können:

    val db: AppDatabase = Room.databaseBuilder(mCtx, AppDatabase::class.java, "db_nam.sqlite").build()

    companion object {
        @SuppressLint("StaticFieldLeak")
        private var mInstance: DatabaseClient? = null

        @Synchronized
        fun getInstance(mCtx: Context): DatabaseClient {
            if (mInstance == null) {
                mInstance = DatabaseClient(mCtx)
            }
            return mInstance as DatabaseClient
        }
    }

    // SEE HERE FOR INSERTING DATA SUCCESSFULLY AND ERROR CODE  
    private fun insertModel(rss_Model: RSS_Model) {
        Completable.fromAction {

            db.database_dao().insertRSS(rss_Model)

        }.observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io()).subscribe(object : CompletableObserver {
                    override fun onSubscribe(d: Disposable) {}

                    override fun onComplete() {
                        // Log.e("onComplete","GET SUCCESS HERE")
                    }

                    override fun onError(e: Throwable) {
                        // Log.e("onError","onError")
                    }
                })
    }

Danke an @Ashwini für die tolle Idee.

@Dao
interface SendDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insert(model: DataModel): Long

    @Update
    suspend fun update(model: DataModel): Int

    @Transaction
    suspend fun insertOrUpdate(model: DataModel): Long {
        val id = insert(model)
        return if (id==-1L) {
            update(model)
            model.id
        } else {
            id
        }
    }
}

Wir sollten also anrufen: database.sendDao().insertOrUpdate(DataModel(...))

Benutzer-Avatar
cinpeCan

@Query("SELECT * FROM pojo WHERE pojo.id = :id")
Maybe<POJO> checkPOJO(String id);

Sie können InsertOrUpdate wie folgt ausführen:

checkPOJO(id).toSingle().concatMapCompletable(pojo->update(pojo))
   .onErrorResumeNext(t -> t instanceof NoSuchElementException ? 
   insert(...): Completable.error

Benutzer-Avatar
Raul Rathore

Sie können auch überprüfen, ob der Eintrag in der Datenbank vorhanden ist oder nicht, Sie können Ihre Logik entsprechend erstellen

Kotlin

@Query("SELECT * FROM Product WHERE productId == :id")
fun isProductExist(id: Int): Boolean

Java

@Query("SELECT * FROM Product WHERE productId == :id")
public boolean isExist(int id);

1216140cookie-checkRaum aktualisieren (oder einfügen, falls nicht vorhanden) Zeilen und Anzahl geänderter Zeilen zurückgeben

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy