【问题标题】:Room Database - Compare values in the database to userinput for validation房间数据库 - 将数据库中的值与用户输入进行比较以进行验证
【发布时间】:2021-12-27 19:40:42
【问题描述】:

我正在创建一个用户可以登录或注册帐户的应用。我已经创建了注册屏幕,它成功地将数据保存到数据库中。但是,我现在正在尝试集成一些验证。例如,用户名必须是唯一的,并且电子邮件不能已经存在。

我当然尝试编写一个自定义查询来打印出用户名列中的所有行,如下所示:

SELECT userName from cx_table

当然,我还尝试编写一个单独的自定义查询来打印出电子邮件列中的所有行,如下所示:

SELECT email from cx_table

然后我的方法是获取用户输入并将其与该列返回的值进行比较,如果存在,则打印一条错误消息。但是当我运行该应用程序时,我收到以下错误消息

The columns returned by the query does not have the fields [id,firstName,lastName,password,address,city,postalcode,email,phone] in com.cxpro.data.Customer even though they are annotated as non-null or primitive. Columns returned by the query: [userName]

这是我的房间数据库的所有代码:


Customer.kt

@Entity(tableName = "cx_table")
data class Customer(
    @PrimaryKey(autoGenerate = true)
    val id: Int,
    val firstName: String,
    val lastName: String,
    val userName: String,
    val password: String,
    val address: String,
    val city: String,
    val postalcode: String,
    val email: String,
    val phone: String
)

CustomerDao.kt

@Dao
interface CustomerDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun addCustomers(customer: Customer)

    @Query("SELECT * FROM cx_table ORDER BY id ASC")
    fun readAllData(): LiveData<List<Customer>>

    @Query("SELECT userName FROM cx_table")
    fun readUserName(): LiveData<List<Customer>>
}

CustomerDatabase.kt

@Database(entities = [Customer::class],version = 1, exportSchema = false)
abstract class CustomerDatabase: RoomDatabase() {

    abstract fun customerDao(): CustomerDao

    companion object{
        @Volatile
        private var INSTANCE: CustomerDatabase? = null

        fun getDatabase(context: Context): CustomerDatabase{
            val tempInstance = INSTANCE
            if(tempInstance != null){
                return tempInstance
            }
            synchronized(this){
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    CustomerDatabase::class.java,
                    "customer_database"
                ).build()
                INSTANCE = instance
                return instance
            }
        }
    }
}

CustomerRepository.kt

class CustomerRepository(private val customerDao: CustomerDao) {
    val readAllData: LiveData<List<Customer>> = customerDao.readAllData()
    val readUserName: LiveData<List<Customer>> = customerDao.readUserName()

    suspend fun addCustomer(customer: Customer){
        customerDao.addCustomers(customer)
    }

}

CustomerViewModel.kt

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

    val readAllData: LiveData<List<Customer>>
    val readUserName: LiveData<List<Customer>>
    private val repository: CustomerRepository

    init {
        val customerDao = CustomerDatabase.getDatabase(application).customerDao()
        repository = CustomerRepository(customerDao)
        readAllData = repository.readAllData
        readUserName = repository.readUserName
    }

    fun addCustomer(customer: Customer){
        viewModelScope.launch(Dispatchers.IO){
            repository.addCustomer(customer)
        }
    }
    
}

如何验证表中不存在用户名和/或电子邮件?

【问题讨论】:

  • this 回答你的问题了吗?
  • 不是真的,你觉得你能澄清一下吗?

标签: kotlin android-room


【解决方案1】:

然后我的方法是获取用户输入并将其与该列返回的值进行比较,如果存在,则打印一条错误消息。但是当我运行该应用程序时,我收到以下错误消息

这是因为没有足够的值来构建客户对象。当您只返回每行一个值时,您可以使用List&lt;String&gt; 而不是List&lt;Customer&gt;如果有多个值,那么您需要一个可能是 POJO 的对象。并且对象字段/变量名称与列名称匹配

但是,您不妨考虑将客户实体更改为:-

,而不是遍历 2 个列表
@Entity(tableName = "cx_table",
    indices = [
        Index(value = ["userName"],unique = true),
        Index(value = ["email"],unique = true)]
)
data class Customer(
    @PrimaryKey(autoGenerate = true)
    val id: Int,
    val firstName: String,
    val lastName: String,
    val userName: String,
    val password: String,
    val address: String,
    val city: String,
    val postalcode: String,
    val email: String,
    val phone: String
)

并且还将插入道更改为:-

@Insert(onConflict = OnConflictStrategy.IGNORE)
fun addCustomers(customer: Customer): Long //<<<<< ADDED Long

可以检查返回值,如果大于0则表示该行已插入,否则该行未插入,无效。

  • 也就是说,由于用户名和电子邮件上的索引是唯一的,因此在复制其中任何一个时尝试插入都会导致冲突,这将被忽略。但是,该行未插入,因此返回 -1。

另一种选择可能是测试这些值,例如

@Query("SELECT count(*) FROM customer WHERE userName=:userNameToCheck OR email=emailToCheck")
fun validateNewCustomer(userNameToCheck: String,emailToCheck): Int

如果结果为 0 则可以插入。如果您想单独检查它们,可以将它们分成两个检查。

您可以使用以下内容确定是用户名还是电子邮件导致无效(非零)结果:-

@Query("SELECT ((SELECT count(*) FROM customer WHERE username=:userNameToCheck) + (SELECT count(*) * 1000 FROM customer WHERE email=:emailToCheck));")
fun validateNewCustomer(userNameToCheck: String,emailToCheck): Int

如果返回值为 0 则有效,如果小于 1000(如果大于 1 则存在重复)则 userName 无效,如果大于 1000 则电子邮件无效,如果大于 1000 但不是精确的倍数1000 那么两者都无效。

    • 1000 最多可容纳 998 个用户名重复(如果用户名上有唯一索引,则应该只有 1 个,类似于电子邮件)

【讨论】:

  • 上帝保佑你神奇的灵魂,我希望你获得永恒的幸福和成功!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
相关资源
最近更新 更多