комнатное обновление (или вставка, если не существует), строки и количество возвращенных строк
Мне нужно обновить, а если нет, добавьте строку в базу данных ROOM.
Я делаю это: productRepository.updateProducts(productsResponse.getProductItems());
А также:
@Override
public void updateProducts(final List<ProductItem> products) {
new Thread(() -> {
for (ProductItem item : products) {
Product product = createProduct(item);
productDao.insert(product);
}
}).start();
}
И в DAO:
@Insert
void insert(Product products);
Но у меня есть метод
@Update
void update(Product product);
И у меня есть несколько вопросов:
-
оба метода недействительны. Как я могу вернуть сохраненный флаг Product или boolean или вставленный счет после вставки?
-
если я попробую выполнить update
и у меня нет строки, она будет вставлена?
-
Как я могу обновить (если нет - вставить) строку и вернуть счетчик обновления или вставленные строки?
Ответы
Ответ 1
-
Метод, аннотированный с помощью @Insert
может возвращать long
. Это вновь созданный идентификатор для вставленной строки. Метод, аннотированный с @Update
может возвращать int
. Это число обновленных строк.
-
update
попытается обновить все ваши поля, используя значение первичного ключа в предложении where
. Если ваша сущность еще не сохраняется в базе данных, запрос на update
не сможет найти строку и ничего не обновит.
-
Вы можете использовать @Insert(onConflict = OnConflictStrategy.REPLACE)
. Это попытается вставить объект, и если существует существующая строка с одинаковым значением идентификатора, она удалит его и заменит на объект, который вы пытаетесь вставить. Имейте в виду, что если вы используете автоматически сгенерированные идентификаторы, это означает, что в полученной строке будет другой идентификатор, чем исходный, который был заменен. Если вы хотите сохранить идентификатор, вы должны придумать собственный способ сделать это.
Ответ 2
Это было какое-то время, но на этот вопрос нет принятого ответа, поэтому я постараюсь это сделать.
Как @Danail Alexiev
сказал @Insert
может возвращать long
. @Update
может вернуть int
.
Но с какой целью вы используете обновление? Если вы просто хотите, чтобы весь объект был заменен новым, просто укажите OnConflictStrategy
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Product products);
Результатом будет: элементы, которые не существуют, будут добавлены, элементы, которые уже существуют, будут заменены новыми.
В случае, если вам нужно обновить только один параметр (например, количество), вы можете сделать что-то вроде этого
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Product products);
@Query("SELECT * from item WHERE id= :id")
void getItemById(int id): List<Product>
@Query("UPDATE item SET quantity = quantity + 1 WHERE id = :id")
void updateQuantity(int id)
void insertOrUpdate(Product item) {
Product itemFromDB = getItemById(item.getId())
if (itemFromDB == null)
insert(item)
else
updateQuantity(item.getId())
}
}
Результат будет таким: Попробуйте поискать элемент в БД, если найден обновить свойство, если не просто вставить новый элемент. Поэтому вам нужно вызвать только один метод insertOrUpdate
из вашего DAO.
Ответ 3
Вы можете проверить свою базу данных, если уже есть элемент с определенным полем, для exmaple:
@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
Элемент - это ваш объект и в вашем коде:
fun insertOrUpdate(item: Item) {
database.runInTransaction {
val id = getItemDao().getItemId(item.id)
if(id == null)
getItemDao().insert(item)
else
getItemDao().update(item)
}
}
Ответ 4
Вы можете проверить ниже метод insertModel(), где вы можете получить метод onComplete() и onError():
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")
}
})
}
Ответ 5
Вы должны использовать Rx Android Single для решения этой проблемы. Пример:
@Query("SELECT * FROM subjectFormTable WHERE study_subject_id ==:subjectFormId")
fun getSubjectForm(subjectFormId: Int): Single<SubjectFormEntity>
Мы используем
val compositeDisposable = CompositeDisposable()
А также
compositeDisposable.add(
subjectFormDao.getSubjectForm(studySubjectId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Log.e(TAG, "successful ")
}, {
Log.e(TAG, "error "+it.message)
//Insert or Update data here
})
)