【问题标题】:How to get id of the inserted entity when using ViewModel?使用 ViewModel 时如何获取插入实体的 id?
【发布时间】:2018-12-05 23:19:16
【问题描述】:

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 但据我所知Repository 应该只负责决定从哪个来源获取或发送数据(例如本地数据库或云)而不是如何存储数据或实体之间的关系。如果有的话,ViewModel 是处理实体关系的地方。
    • 你是对的,你应该创建 UseCaseClass 来实现 Repository 并保存你需要的所有逻辑。在您的ViewModel 中,您应该实现这个UseCaseClass 并使用它。我不知道你为什么还在使用AsyncTask ;/
    【解决方案2】:

    您可以使用 Android Room 在一个事务中执行多个数据库操作。 这样,您可以确保在其中一个操作失败(操作被回滚)的情况下不会改变您的数据库完整性。

    以下是如何在 Dao 类中定义带有 Room 的事务:

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

    您可以参考documentation 了解@Transaction 的工作原理。

    然后在您的存储库类中,从您的AsyncTask 调用buyItemFromStore

    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

    【讨论】:

      猜你喜欢
      • 2012-08-30
      • 2023-03-16
      • 2018-12-12
      • 1970-01-01
      • 1970-01-01
      • 2011-07-24
      • 1970-01-01
      • 1970-01-01
      • 2019-11-24
      相关资源
      最近更新 更多