繁体   English   中英

如何通过mvvm体系结构使Room数据库插入方法返回int?

[英]How to make Room database insert method return int through mvvm architecture?

我想在Room数据库上执行插入操作时自动生成ID。 我正在实现MVVM(模型-视图-视图模型)体系结构,该体系结构使用DAO向Room数据库发出查询。 我在viewmodel和DAO之间添加了一个存储库层,以创建一个AsyncTask来执行数据库操作。 如何获取对使用viewmodel的片段的插入操作(插入行的自动生成的ID)的输出。 这些层如下:片段-> ViewModel->存储库-> DAO

ListFragment.java

public class ListFragment extends Fragment {
    private ReminderViewModel viewModel;
    private int id;
    ...
        viewModel = ViewModelProviders.of(this).get(ReminderViewModel.class);
    ...
        id = viewModel.insert(new TodoReminder(0, description, date, time));
    ...
}

ReminderViewModel.java

public class ReminderViewModel extends AndroidViewModel {
    private ReminderRepository repository;

    public ReminderViewModel(@NonNull Application application) {
        super(application);
        repository = new ReminderRepository(application);
    }

    public int insert(TodoReminder reminder) {
        repository.insert(reminder);
    }
}

ReminderRepository.java

public class ReminderRepository {
    private ReminderDAO reminderDAO;

    public ReminderRepository(Application application) {
        AppDatabase db = AppDatabase.getDatabase(application);
        reminderDAO = db.getReminderDAO();
    }

    public int insert(TodoReminder reminder) {
        new insertAsyncTask(reminderDAO).execute(reminder);
    }

    private static class InsertAsyncTask extends AsyncTask<TodoReminder, Void, Integer> {
        private ReminderDAO asyncTaskDAO;

        insertAsyncTask(ReminderDAO dao) {
            asyncTaskDAO = dao;
        }

        @Override
        protected Integer doInBackground(final TodoReminder... reminders) {
            return asyncTaskDAO.insert(reminders[0]);
        }
    }
}

提醒DAO.java

@Dao
public interface ReminderDAO {
    @Insert
    public int insert(TodoReminder... reminders);
}

ToDoReminder.java

public class TodoReminder implements Serializable {
    @PrimaryKey(autoGenerate = true)
    @NonNull
    private int id;
    ...
}

我应该如何获取从ReminderDAO的insert方法返回的int并从ReminderRepository中的insert方法返回它?

您可以以自动增加id的方式创建database表。 在MySQL中,是通过auto_increment关键字完成的。 在SQL Server中,这是通过identity(1, 1)语法完成的。 在Access中,它是autoincrement关键字。 在Oracle和PostgreSQL中,使用sequence s完成。 如果您能够做到这一点,那么您将不需要手动增加这些值。 如果出于某种原因这是不可能的,那么您可以创建一个before insert触发器,该触发器将加载最大ID并将其添加1,并将结果存储在ID中。 或者,即使这是不可能的,您也可以加载最后一个ID,但是在不同的数据库中它具有不同的语法。 或者,您可以运行如下查询:

select max(id) + 1 from yourtable;

但要注意可能的性能问题和并发问题。

我有确切的问题。 这就是我所做的。

我创建了一个界面

public interface Task
 {
    void processInsert(long id) 
}

为存储库中的插入fcn提供接口

public class Repository {

private Dao myDao;


    public void insertMyObject(MyOBject object,Task myInterface ) {

         new insertAysncTask(myDao,myInterface).execute(object);
      }

    private static class insertAsyncTask extends AysncTask<MyObject,Void,Long>{
        private Dao mDao;
        private Task mTask;

        public insertAysncTask(Dao dao, Task task) {

            this.mDao = dao;
            this.mTask=task;
        }


        @Override
        protected Long doInBackground(MyObject... myObjects) {
            return mDao.insertMyObject(myObjects[0]);

        }

        @Override
        protected void onPostExecute(Long aLong) {
            super.onPostExecute(aLong);
            mTask.processInsert(aLong);
        }
    }


}

在DAO类中,fcn应该具有Long类型的返回类型

public interface MyDao {
    @Insert
    Long insertMyObject(MyObject object);

让ViewModel实现接口

 public class MyObjectViewModel extends AndroidViewModel implements Task{

    private Repository mRepository;

    public MyObjectViewModel(@NonNull Application application) {
        super(application);
        mRepository = new Repository(application);
    }

    @Override
    public void processInsert(Long id) {

      // code for processing the id returned from the db insert

    }

    public void insertMyObject(MyObject object){

        mRepository.insertMyObject(object,this);}


}

在活动/片段中,调用ViewModel插入

mViewModel.insertMyObject(object);

更新资料

如果要将ID返回给活动或片段,则让片段/活动实现接口而不是viewmodel

ListFragment extends Fragment implements Task{
.....

@Override
public void processInsert(Long id){
   //process id here
  }

//call the insert fcn passing in the reference to the fragment

mViewModel.insertMyObject(object,this)
}

修改视图模型中的insert fcn以接受对接口的引用

public void insertMyObject(MyObject object, Task myInterface){

        mRepository.insertMyObject(object,myInterface);
}

通过这种方法,存储库插入文件fcn中的asynctask将保存对活动/片段的引用,并且如果在asynctask完成之前销毁了活动/片段,将是一个问题。 我认为最好在视图模型中进行处理。 片段/活动应仅处理UI问题,而不涉及数据处理。

替代方法替代方法是将LiveData与观察者一起使用。

public class Repository{

private Dao myDao;
private MutableLiveData<Long> dbInsertId = new MutableLiveData<>();

public void insertMyObject(MyObject object){

    insertAysnc(object)
  }

private void insertAysnc(final MyObject object){

   new Thread(new Runnable() {
            @Override
            public void run() {
                Long id=myDao.insertMyObject(object); //call Dao insert fcn
              dbInsertId.postValue(id); //set the value of the livedata to the valued returned from the DB insert fcn
            }
        }).start();
  }

public LiveData<Long> getDbInsertedId(){
        return dbInsertId;
    }

}

在ViewModel中定义此fcn

public LiveData<Long> getDbInsertedId(){
        return mRepository.getDbInsertedId();// call the repository getId fcn
    }

在活动/片段的onCreate中设置LiveData上的观察者

mViewModel= ViewModelProviders.of(this).get(MyViewModel.class);
mViewModel.getDbInsertedId().observe(this, new Observer<Long>() {
            @Override
            public void onChanged(Long aLong) {
               // do something with the long value returned from the database
            }
        });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM