Android Studio - Room Persistence Library - 确保用户输入的主键在插入数据库之前是唯一的

Android Studio - Room Persistence Library - Ensuring that the Primary Key a user enters is unique before inserting into the database

我正在学习如何在 Android Studio 中使用 Room Persistence Library,它基本上是 SQLite 之上的抽象层,使数据库更容易。

在我的示例应用程序中,我允许用户输入非常基本的学生信息:

我已经为数据库创建了以下三个必要的组件:

1.实体(学生)

package com.aleks.firstdatabaseproject;

import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;

/* This is one entity that will be stored in our database. A Student has a
 * unique ID, a first name, and a last name.
 */

@Entity
public class Student {

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "first_name")
    private String firstName;

    @ColumnInfo(name = "last_name")
    private String lastName;

    @ColumnInfo(name = "email")
    private String email;

    @ColumnInfo(name="notes")
    private String notes;

    public Student() { this("", "", "", ""); }

    public Student(String firstName, String lastName, String email, String notes) {
        setFirstName(firstName);
        setLastName(lastName);
        setEmail(email);
        setNotes(notes);
    }

    public void setId(int id){ this.id = id; }

    public void setFirstName(String firstName) { this.firstName = firstName; }

    public void setLastName(String lastName) { this.lastName = lastName; }

    public int getId() { return this.id; }

    public String getFirstName() { return this.firstName; }

    public String getLastName() { return this.lastName; }

    public String getNotes() { return notes; }

    public void setNotes(String notes) { this.notes = notes; }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

2。数据访问对象 API

package com.aleks.firstdatabaseproject;

import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;

import com.aleks.firstdatabaseproject.Student;

import java.util.List;

/* A Data Access Object (DAO) provides an abstracted interface that allows
 * a user program to request information from the database. The DAO provides
 * methods for insertion, deletion, and querying in the database.
 */

@Dao
public interface StudentDAO {

    @Insert
    void addStudent(Student student);

    @Delete
    void removeStudent(Student student);

    @Query("SELECT * FROM Student")
    List<Student> getAllStudents();

    @Query("SELECT * FROM Student WHERE id IS :studentID")
    Student findStudentByID(int studentID);

    @Query("SELECT * FROM Student WHERE first_name LIKE :first AND last_name LIKE :last")
    List<Student> findStudentByName(String first, String last);
}

3。数据库

package com.aleks.firstdatabaseproject;

import android.arch.persistence.room.Database;
import android.arch.persistence.room.RoomDatabase;

import com.aleks.firstdatabaseproject.Student;
import com.aleks.firstdatabaseproject.StudentDAO;

@Database(entities = {Student.class}, version = 1)
public abstract class StudentDatabase extends RoomDatabase {

    /* Used by apps to get the data access object from the database */
    public abstract StudentDAO studentDAO();
}

作为参考,这里是主要的 activity:

主要Activity

package com.aleks.firstdatabaseproject;

import android.arch.persistence.room.Room;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import org.w3c.dom.Text;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static StudentDatabase mDatabase;
    private StudentDAO mStudentDAO;
    private TextView mFirstName;
    private TextView mLastName;
    private TextView mId;
    private TextView mEmail;
    private TextView mNotes;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDatabase = Room.databaseBuilder(getApplicationContext(),
                StudentDatabase.class, "database-name").build();
        mStudentDAO = mDatabase.studentDAO();

        mFirstName = (TextView) findViewById(R.id.editText_firstName);
        mLastName = (TextView) findViewById(R.id.editText_lastName);
        mId = (TextView) findViewById(R.id.editText_id);
        mEmail = (TextView) findViewById(R.id.editText_email);
        mNotes = (TextView) findViewById(R.id.editText_notes);
    }

    /* Uses the information in the app's main fields to build and
     * return a new Student object for use by other methods.
     */
    public Student buildStudentFromFields() {
        String firstName = mFirstName.getText().toString();
        String lastName = mLastName.getText().toString();
        String email = mEmail.getText().toString();
        String notes = mNotes.getText().toString();
        return new Student(firstName, lastName, email, notes);
    }

    /* Called when the user clicks the "ADD" button. Inserts
     * the given Student into the database.
     */
    public void addStudent(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                mStudentDAO.addStudent(buildStudentFromFields());
            }
        }).start();
    }

    /* Called when the user clicks the "REMOVE" button. Removes
     * the given Student from the database.
     */
    public void removeStudent(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                mStudentDAO.removeStudent(buildStudentFromFields());
            }
        }).start();
    }

    /* Called when the user clicks the "FIND" button. Returns
     * information about the given Student from the database.
     */
    public void findStudent(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Student student = mStudentDAO.findStudentByID(Integer.parseInt(mId.getText().toString()));
            }
        }).start();
    }
}

我想做什么

您会注意到实体 class 中包含了注释 @PrimaryKey(autogenerate = true)。这将 id 字段指定为 Student table 的主键,并且 autogenerate 选项强制数据库生成自己的主键而不是用户有意识地记住传入一个唯一的密钥。但是用户很容易出错,他们可能会不小心点击两次 ADD 按钮,例如

问题是:我想允许用户像我在屏幕截图中显示的那样传入他们自己的自定义学生 ID,但如果用户尝试(非法)输入相同的学生 ID,则会出现问题两次——应用在这种情况下崩溃。

一个可能的解决方案是保留用户目前输入的所有 ID 的 set/hash table,并在尝试 ADD 之前确保他们输入的内容是唯一的学生到数据库。但这只会占用比看起来需要更多的内存(对于这么小的应用程序来说不是很多,但存储额外的 "junk" 信息似乎不合理)。

有什么方法可以解决重复的主键,以防止用户意外输入同一个学生 ID 两次时应用程序崩溃?

您可以尝试在Insert 方法中定义OnConflictStrategy 来处理错误,检查这个link