Как получить идентификатор вставленной сущности при использовании ViewModel? - PullRequest
0 голосов
/ 06 декабря 2018

Корневая проблема: я хочу установить идентификатор [Entity A] во внешнем ключе [Entity B], но идентификатор [Entity A] недоступен, пока не вставлен в базу данных (потому что он автоматически генерируетсяСУБД).

Используя компоненты архитектуры (Room, ViewModel и LiveData), как я могу выполнить транзакцию, которая сохраняет несколько связанных объектов в базе данных?Следующий код в настоящее время находится в ViewModel и работает нормально.Проблема в том, что я хочу поместить этот AsyncTask в слой хранилища, как и другие простые однооперационные запросы, но нормально ли это?Потому что в этом случае хранилище будет отвечать за управление отношениями и знание деталей сущности.

Как я уже говорил выше, основная проблема заключается в том, что мне нужен идентификатор вставленной сущности, чтобы я мог сохранить ее в другой сущности.Если бы это требование не существовало, я мог бы сохранять каждую сущность по одному в отдельных AsyncTask s в хранилище.

MainViewModel.java:

public void buy(Item item, Store store) {

    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... voids) {
            long storeId = mRepository.insertStore(store);

            Purchase purchase = new Purchase(storeId); // here uses id of the store
            long purchaseId = mRepository.insertPurchase(purchase);

            item.setPurchaseId(purchaseId); // here uses id of the purchase
            mRepository.updateItem(item);

            return null;
        }
    }.execute();
}

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Вы можете выполнить несколько операций с базой данных в транзакции, используя Android Room.Таким образом, вы гарантируете, что целостность вашей базы данных не будет изменена в случае сбоя одной из этих операций (откат операций).

Вот как вы можете определить транзакцию с комнатой в классе Dao:

@Dao
public abstract class MyDao {

    @Insert
    public abstract long insertStore(Store store);

    @Insert(onConflict = OnConflictStrategy.ROLLBACK)
    public abstract long recordPurchase(Purchase purchase);

    @Update
    public abstract void updateItem(Item updatedItem);

    @Transaction
    public void buyItemFromStore(Item boughtItem, Store store) {
        // Anything inside this method runs in a single transaction.
        long storedId = insertStore(store);

        Purchase purchase = new Purchase(storeId);
        long purchaseId = recordPurchase(purchase);

        item.setPurchaseId(purchaseId);
        updateItem(item);
    }
}

Вы можете обратиться к документации для объяснения того, как работает @Transaction.

Затем в своем классе репозитория вызовите buyItemFromStore изваш AsyncTask:

public class MyRepository {
    private MyDao dao;

    public void buy(Item item, Store store) {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doOnBackground(Void... voids) {
                // Everything is saved in a transaction.
                dao.buyItemFromStore(item, store);
                return null;
            }
        }
    }
}

Обратите внимание, что для слоя Repository это прекрасно, если вы знаете о связях между сущностями, если хранимые объекты связаны каким-либо образом (с помощью функции «Покупка из магазина» иПохоже, что это так).

Если вы не можете изменить класс Dao, рассмотрите RoomDatabase.runInTransaction.

0 голосов
/ 19 декабря 2018

Я думаю, что вы делаете хорошо, если вы держите это в слое Repository.Я не думаю, что хранить это во ViewModel - это хорошая идея, поскольку предполагается, что ответственность за обработку ваших данных лежит на репозитории, в данном случае на объектах Item и Store.Я считаю, что ваш репозиторий должен нести ответственность за управление этими данными и их отношения.Чтобы ответить на ваш вопрос о получении идентификатора обновленной сущности, вы можете сделать так, чтобы AsyncTask реализовал метод onPostExecute, а метод doInBackground возвратил фактическое значение (например, storeId) вместо null,Затем вы можете onPostExecute получить это значение и передать управление прослушивателю обратного вызова некоторого вида.

...