Android房间-自动生成新插入行的id

这是我如何使用房间持久性库插入数据到数据库:

实体:

@Entity
class User {
@PrimaryKey(autoGenerate = true)
public int id;
//...
}

数据访问对象:

@Dao
public interface UserDao{
@Insert(onConflict = IGNORE)
void insertUser(User user);
//...
}

是否有可能返回用户的id一旦插入完成在上面的方法本身,而不编写一个单独的选择查询?

122733 次浏览

@Insert函数可以返回voidlonglong[]List<Long>。请尝尝这个。

 @Insert(onConflict = OnConflictStrategy.REPLACE)
long insert(User user);


// Insert multiple items
@Insert(onConflict = OnConflictStrategy.REPLACE)
long[] insert(User... user);

基于文档在这里(代码片段下面)

@Insert注释的方法可以返回:

  • long用于单个插入操作
  • 用于多个插入操作的long[]Long[]List<Long>
  • void如果你不关心插入的id

如果语句成功,一条记录的插入返回值将为1。

如果你想插入对象列表,你可以使用:

@Insert(onConflict = OnConflictStrategy.REPLACE)
public long[] addAll(List<Object> list);

然后用Rx2执行:

Observable.fromCallable(new Callable<Object>() {
@Override
public Object call() throws Exception {
return yourDao.addAll(list<Object>);
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
// the o will be Long[].size => numbers of inserted records.


}
});

在你的Dao中,插入查询返回Long即插入的rowId。

 @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(recipes: CookingRecipes): Long

在您的模型(存储库)类:(MVVM)

fun addRecipesData(cookingRecipes: CookingRecipes): Single<Long>? {
return Single.fromCallable<Long> { recipesDao.insertManual(cookingRecipes) }
}

在您的ModelView类:(MVVM)处理LiveData与DisposableSingleObserver.
工作源引用:https://github.com/SupriyaNaveen/CookingRecipes

通过下面的复选框获取行ID。它在带有Future的ExecutorService上使用callable。

 private UserDao userDao;
private ExecutorService executorService;


public long insertUploadStatus(User user) {
Callable<Long> insertCallable = () -> userDao.insert(user);
long rowId = 0;


Future<Long> future = executorService.submit(insertCallable);
try {
rowId = future.get();
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return rowId;
}

关于Callable的更多信息,参考:Java Executor服务教程

经过一番努力,我终于解决了这个问题。下面是我使用MMVM架构:的解决方案

Student.kt

@Entity(tableName = "students")
data class Student(
@NotNull var name: String,
@NotNull var password: String,
var subject: String,
var email: String


) {


@PrimaryKey(autoGenerate = true)
var roll: Int = 0
}

StudentDao.kt

interface StudentDao {
@Insert
fun insertStudent(student: Student) : Long
}

StudentRepository.kt

    class StudentRepository private constructor(private val studentDao: StudentDao)
{


fun getStudents() = studentDao.getStudents()


fun insertStudent(student: Student): Single<Long>? {
return Single.fromCallable(
Callable<Long> { studentDao.insertStudent(student) }
)
}


companion object {


// For Singleton instantiation
@Volatile private var instance: StudentRepository? = null


fun getInstance(studentDao: StudentDao) =
instance ?: synchronized(this) {
instance ?: StudentRepository(studentDao).also { instance = it }
}
}
}

StudentViewModel.kt

class StudentViewModel (application: Application) : AndroidViewModel(application) {


var status = MutableLiveData<Boolean?>()
private var repository: StudentRepository = StudentRepository.getInstance( AppDatabase.getInstance(application).studentDao())
private val disposable = CompositeDisposable()


fun insertStudent(student: Student) {
disposable.add(
repository.insertStudent(student)
?.subscribeOn(Schedulers.newThread())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribeWith(object : DisposableSingleObserver<Long>() {
override fun onSuccess(newReturnId: Long?) {
Log.d("ViewModel Insert", newReturnId.toString())
status.postValue(true)
}


override fun onError(e: Throwable?) {
status.postValue(false)
}


})
)
}
}

在片段中:

class RegistrationFragment : Fragment() {
private lateinit var dataBinding : FragmentRegistrationBinding
private val viewModel: StudentViewModel by viewModels()


override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initialiseStudent()
viewModel.status.observe(viewLifecycleOwner, Observer { status ->
status?.let {
if(it){
Toast.makeText(context , "Data Inserted Sucessfully" , Toast.LENGTH_LONG).show()
val action = RegistrationFragmentDirections.actionRegistrationFragmentToLoginFragment()
Navigation.findNavController(view).navigate(action)
} else
Toast.makeText(context , "Something went wrong" , Toast.LENGTH_LONG).show()
//Reset status value at first to prevent multitriggering
//and to be available to trigger action again
viewModel.status.value = null
//Display Toast or snackbar
}
})


}


fun initialiseStudent() {
var student = Student(name =dataBinding.edName.text.toString(),
password= dataBinding.edPassword.text.toString(),
subject = "",
email = dataBinding.edEmail.text.toString())
dataBinding.viewmodel = viewModel
dataBinding.student = student
}
}

我使用过数据绑定。这是我的XML:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">


<data>


<variable
name="student"
type="com.kgandroid.studentsubject.data.Student" />


<variable
name="listener"
type="com.kgandroid.studentsubject.view.RegistrationClickListener" />


<variable
name="viewmodel"
type="com.kgandroid.studentsubject.viewmodel.StudentViewModel" />


</data>




<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context="com.kgandroid.studentsubject.view.RegistrationFragment">


<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constarintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:isScrollContainer="true">


<TextView
android:id="@+id/tvRoll"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:gravity="center_horizontal"
android:text="Roll : 1"
android:textColor="@color/colorPrimary"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


<EditText
android:id="@+id/edName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:ems="10"
android:inputType="textPersonName"
android:text="Name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvRoll" />


<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="Name:"
android:textColor="@color/colorPrimary"
android:textSize="18sp"
app:layout_constraintBaseline_toBaselineOf="@+id/edName"
app:layout_constraintEnd_toStartOf="@+id/edName"
app:layout_constraintStart_toStartOf="parent" />


<TextView
android:id="@+id/tvEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Email"
android:textColor="@color/colorPrimary"
android:textSize="18sp"
app:layout_constraintBaseline_toBaselineOf="@+id/edEmail"
app:layout_constraintEnd_toStartOf="@+id/edEmail"
app:layout_constraintStart_toStartOf="parent" />


<EditText
android:id="@+id/edEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:ems="10"
android:inputType="textPersonName"
android:text="Name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edName" />


<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Password"
android:textColor="@color/colorPrimary"
android:textSize="18sp"
app:layout_constraintBaseline_toBaselineOf="@+id/edPassword"
app:layout_constraintEnd_toStartOf="@+id/edPassword"
app:layout_constraintStart_toStartOf="parent" />


<EditText
android:id="@+id/edPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:ems="10"
android:inputType="textPersonName"
android:text="Name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edEmail" />


<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="32dp"
android:background="@color/colorPrimary"
android:text="REGISTER"
android:onClick="@{() -> viewmodel.insertStudent(student)}"
android:textColor="@android:color/background_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edPassword" />
</androidx.constraintlayout.widget.ConstraintLayout>




</androidx.core.widget.NestedScrollView>
</layout>

我已经挣扎了很多,以完成这与asynctask作为房间插入和删除操作必须在一个单独的线程。终于能够做到这一点与

根据文档函数加上@Insert可以返回rowId。

如果@Insert方法只接收到1个参数,它可以返回一个long,即插入项的新rowId。如果参数是数组或集合,则应返回long[]或List< long >代替。

我有这个问题是,它返回rowId而不是id,我仍然没有找到如何使用rowId获得id。

编辑:我现在知道如何从rowId获取id。下面是SQL命令:

SELECT id FROM table_name WHERE rowid = :rowId
如果@Insert方法接收到单个参数,它可以返回一个长值,即插入项的新rowId。 在这里输入链接描述 < / p >
@Insert
suspend fun insert(myEntity: MyEntity):Long