使用ViewModel时如何获取插入实体的ID?

时间:2018-12-05 23:19:17

标签: java android android-asynctask android-room android-viewmodel

根本问题:我想在[实体B]的外键中设置[实体A]的ID,但是[实体A]的ID在插入数据库之前不可用(因为它是由数据库自动生成的) DBMS)。

使用体系结构组件(Room,ViewModel和LiveData),如何执行将多个相关实体保存在数据库中的事务?以下代码当前位于ViewModel中,并且运行正常。问题是我想像其他简单的单操作查询一样将此AsyncTask放入存储库层,但是可以吗?因为在这种情况下,存储库将负责管理关系并了解实体详细信息。

如上所述,主要问题是我需要插入实体的ID,以便可以将其保存在另一个实体中。如果不存在此要求,我将能够在存储库中单独的AsyncTask中一个一个地持久保存每个实体。

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 :(得分:1)

如果将其保存在“存储库”层中,我认为您正在做的事很好。我认为将其保留在ViewModel中并不是一个好主意,因为这是存储库负责处理数据的责任,在这种情况下,ItemStore对象是您的责任。我相信您的存储库应该负责此数据及其关系的管理。要回答有关接收更新后的实体的ID的问题,您可以做的是让AsyncTask实现onPostExecute方法,并使doInBackground方法返回实际值(例如storeId ),而不是null。然后,您可以让onPostExecute检索该值并将控制委托给某种回调侦听器。

答案 1 :(得分:0)

您可以使用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的工作原理,您可以参考documentation

然后在您的存储库类中,从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;
            }
        }
    }
}

请注意,只要存储的对象以某种方式关联(对于Store Purchase和Item来说似乎如此),Repository层就可以很好地了解实体之间的关系。

如果您无法更改自己的Dao类,请考虑使用RoomDatabase.runInTransaction