The columns returned by the query does not have the fields [id,password] - android-room

I have log in app with pre populated database (ROOM).
When i'm logging in I need to check email and password in database then after that if email and password are correct, show final fragment. But i have error which is higher.
I was searching but nothing helps me.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.continuebutton.setOnClickListener {
if(binding.EmailSpace.length() == 0){
Toast.makeText(context,"Поле пустое введите email",Toast.LENGTH_SHORT).show()
}
if(binding.PasswordSpace.length() == 0){
Toast.makeText(context,"Поле пустое введите пароль",Toast.LENGTH_SHORT).show()
}
if(binding.PasswordSpace.length() <8){
Toast.makeText(context,"Пароль слишком короткий",Toast.LENGTH_SHORT).show()
}
val espace = binding.EmailSpace.text.toString()
val pspace = binding.EmailSpace.text.toString()
if(espace.isNotEmpty() && pspace.isNotEmpty()){
check(espace == "admin#gmail.com")
check(pspace == "12345678")
scope.launch {
db.getDAO().findbyEmail(espace)
db.getDAO().findbypassword((pspace))
}
findNavController().navigate(R.id.action_loginFragment_to_lastfragment)
} else{
Toast.makeText(context,"Данные введены не верно",Toast.LENGTH_SHORT)
}
}
}
This is a fragment in which i'm checking edittexts for empty.
AdminDatabaseclass
import Room.DAO.DAO
import Room.Repository.Admindata
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
#Database (entities = [Admindata::class], version = 1, exportSchema = true)
abstract class AdminDatabase:RoomDatabase(){
abstract fun getDAO(): DAO
companion object{
fun getadminDB(context: Context):AdminDatabase{
return Room.databaseBuilder(context.applicationContext,AdminDatabase::class.java,"admindb").createFromAsset("SQLDB/dbforpetproject.db").build()
}
}
DAO
#Dao
interface DAO {
#Query("select email from admindb where email = :email")
suspend fun findbyEmail(email:String) : Admindata
#Query("select password from admindb where password = :password")
suspend fun findbypassword(password:String) : Admindata
}
Admindata
#Entity(tableName= "admindb")
data class Admindata(
#PrimaryKey
val id:Int = 1,
#ColumnInfo(name = "email")
val email:String = "admin#gmail.com",
#ColumnInfo(name = "password")
val password :String = "12345678"
)
Error after launching how it looks like enter image description here
Another one screenshot enter image description here

You want to use
#Dao
interface DAO {
#Query("select * from admindb where email = :email")
suspend fun findbyEmail(email:String) : Admindata
#Query("select * from admindb where password = :password")
suspend fun findbypassword(password:String) : Admindata
}
Then the Admindata returned will have all the values from the database rather than just the email (findbyEmail) or the password (findbyPassword).
The * represents all columns, which is the equivalent of SELECT id, email, password FROM admindb ....

Related

Is there a way to make relation to Set<String> in Room?

Assume tables:
CREATE TABLE users (id INT, name VARCHAR(255))
CREATE TABLE user_roles (user_id INT REFERENCES users(id), role_name VARCHAR(255))
Entity in Room:
#Entity(tableName = "users")
data class User(
#PrimaryKey
val id: Int,
val roles: Set<String> // want it from role_name column
)
Second entity (if needed):
#Entity(tableName = "user_roles")
data class UserRole(
val user_id: Int,
val role_name: String
)
DAO
#Dao
interface UserDao {
#Query("SELECT * FROM users")
fun getAllUsers(): Flow<List<User>>
}
This will not compile because SQLite doesn't support collections. Is there any way to map the role_name from user_roles to roles property of User entity? Can Room do it automatically?
I don't think Room has automatic support for that requirement. Instead you could do a custom query to achieve that.
Refer to this example of how to do one, and adapt according to your requirements.
getAllUsersWithRoles returns flow of list of UserWithRoles. Query joins users and user_roles tables and maps results to UserWithRolesResult class.
fromResult takes list of UserWithRolesResult and maps it to list of UserWithRoles
#Dao
interface UserDao {
#Transaction
#Query("SELECT * FROM users")
fun getAllUsersWithRoles(): Flow<List<UserWithRoles>>
companion object {
private fun fromResult(result: List<UserWithRolesResult>) : List<UserWithRoles> {
val map = result.groupBy { it.userId }.mapValues { it.value.map { it.roleName }.toSet() }
return map.map { UserWithRoles(it.key, it.value) }
}
}
}
data class UserWithRoles(
val userId: Int,
val roles: Set<String>
)
data class UserWithRolesResult(
val userId: Int,
val roleName: String
)
This will not compile because SQLite doesn't support collections.
Room however does.
Consider the following working Demo based upon your code
note the comments and modifications
run on the main thread for brevity
the POJO UserWithRoles is the main inclusion that uses a Set, which is populated/used
:-
#Entity(tableName = "users")
data class User(
#PrimaryKey
val id: Int,
val name: String
/* roles would be effectively trying to store what is stored elsewhere */
//val roles: Set<String> // want it from role_name column !! Wrong place see UserWithRoles
)
#Entity(
tableName = "user_roles",
foreignKeys = [
ForeignKey(
entity = User::class,
parentColumns = ["id"],
childColumns = ["user_id"]
)
]
)
data class UserRole(
#PrimaryKey
/* In Room and Entity MUST have a primary key */
/* if user_id were a primary key then many UserRoles per User would not be allowed as
a primary key is implicitly UNIQUE. Hence dummy_id
*/
val dummy_id: Long?=null,
val user_id: Int,
val role_name: String
)
data class UserWithRoles(
#Embedded
val user: User,
#Relation(entity = UserRole::class, parentColumn = "id", entityColumn = "user_id" )
val roles: Set<UserRole>
)
#Dao
interface UserDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(user: User): Long
#Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(userRole: UserRole): Long
#Query("SELECT * FROM users")
fun getAllUsers(): /*Flow<*/List<UserWithRoles>/*>*/
}
#Database(entities = [User::class,UserRole::class], exportSchema = false, version = 1)
abstract class TheDatabase: RoomDatabase() {
abstract fun getUserDao(): UserDao
companion object {
private var instance: TheDatabase?=null
fun getInstance(context: Context): TheDatabase {
if (instance==null) {
instance=Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
.allowMainThreadQueries() /* for brevity of demo */
.build()
}
return instance as TheDatabase
}
}
}
and some Activity Code to demonstrate:-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: UserDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getUserDao()
dao.insert(User(10,"Fred"))
dao.insert(User(11,"Mary"))
dao.insert(User(12,"Jane"))
dao.insert(UserRole(user_id = 10, role_name = "Role1"))
dao.insert(UserRole(user_id = 10, role_name = "Role2"))
dao.insert(UserRole(user_id = 10, role_name = "Role3"))
dao.insert(UserRole(user_id = 11, role_name = "Role4"))
for (uwr in dao.getAllUsers()) {
val sb = StringBuilder()
for (r in uwr.roles) {
sb.append("\n\tRole is ").append(r.role_name)
}
Log.d("DBINFO","User is ${uwr.user.name} and has ${uwr.roles.size} roles. They are ${sb}")
}
}
}
When run then the log includes:-
D/DBINFO: User is Fred and has 3 roles. They are
Role is Role3
Role is Role2
Role is Role1
D/DBINFO: User is Mary and has 1 roles. They are
Role is Role4
D/DBINFO: User is Jane and has 0 roles. They are

How to combine key and value using Jackson (Spring boot)

I have json like below.
{
"USER0001": {
"name": "hoge",
"age": 20
},
"USER0002": {
"name": "huga",
"age": 10
}
}
and, this is my User data class.
data class User(
val id: String,
val name: String,
val age: Int
)
then, I want to convert json to user list when request is send controller.
listOf(
User("USER0001", "hoge", 20),
User("USER0002", "huga", 10),
)
and my controller .
#RestController
class MyController() {
fun test(#RequestBody users: List<User>) {
// some code. I want to use users as List<User>
}
}
I try using #JsonComponent like below,
class Deserializer : JsonDeserializer<List<User>>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): List<User> {
val treeNode = parser.codec.readTree<TreeNode>(parser)
val fieldNames = treeNode.fieldNames()
val result = mutableListOf<User>()
while(fieldNames.hasNext()) {
val fieldName = fieldNames.next()
val userJson = treeNode.get(fieldName)
// I can't use this code as String type.
val name = userJson.get("name")
// How Can I make User model ???
}
return result
}
}
then, I don't know how to make User object in deserializer method.
do you know how to do this ?
thank you reading.
this is simple way.
#RestController
class MyController() {
fun test(#RequestBody Map<String, UserDetail>) {
// some code...
}
}

How to select from database with "where" parameter SpringBoot?

I would like to get one single entry from database. I have such entry model:
#Table("USERS")
data class User(#Id val id: String?, val login: String, val password: String)
and such controller:
#RestController
class MessageResource(val service: MessageService) {
#GetMapping
fun index(): List<User> = service.findMessages()
#PostMapping
fun post(#RequestBody user: User) {
service.post(user)
}
#GetMapping("/user")
fun getByLogin(#RequestParam("login") login: String): User? = service.getByUser(login)
}
such service:
#Service
class MessageService(val db: MessageRepository) {
fun findMessages(): List<User> = db.findMessages()
fun post(user: User) {
db.save(user)
}
fun getByUser(login: String) = db.getByUser(login)
}
and repository:
interface MessageRepository : CrudRepository<User, String> {
#Query("select * from users")
fun findMessages(): List<User>
#Query(value = "select * from users")
fun getByUser(login: String): User? {
val sql = "SELECT * FROM users WHERE login = $login"
return JdbcTemplate().queryForObject(sql, User::class.java)
}
}
I'm little bit new in SprinBoot and I'm trying to get one entry from database. I tried to run it in repository getByUser method, by received error:
org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 4
maybe I did it in wrong way and I have to use another method for filtering all table by row value?
The method JdbcTemplate().queryForObject in repository expected to return only 1 row by the SELECT statement.
If your statement is returning multiple results, you should consider to use JdbcTemplate().query and the getByUser() method in repository should return List<User>.
query doc
fun getByUser(login: String): List<User>? {
val sql = "SELECT * FROM users WHERE login = $login"
return JdbcTemplate().query(sql, new BeanPropertyRowMapper(User::class.java))
}
If you expected only one record returned by database. Here is another easier solution.
If you are using mysql:
fun getByUser(login: String): User? {
val sql = "SELECT * FROM users WHERE login = $login limit 1"
return JdbcTemplate().queryForObject(sql, User::class.java)
}
If you are using Oracle:
fun getByUser(login: String): User? {
val sql = "SELECT * FROM users WHERE login = $login and rownum=1"
return JdbcTemplate().queryForObject(sql, User::class.java)
}

createFromFile( ) doesn't populate database - Room

EDIT: 09/30
Thanks to #shb, I've determined that createFromFile() is not properly populating the database as intended.
If anyone can point out what I'm doing wrong/missing, that would be great! Please refer to the below picture for reference on the database structure. Thanks in advance!
MainActivity
class MainActivity: AppCompatActivity() {
lateinit var mDatabase: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mDatabase = AppDatabase.getInstance(this)
}
fun getFacilityNbr() {
val planInfo = mDatabase.getPlanInfoDao().getPlanInfo()
Log.d("MainActivity", "Size = ${planInfo.size}") // 0
}
}
AppDatabase
#Database(entities = [PlanInfo::class], version = 1)
abstract class AppDatabase: RoomDatabase() {
companion object {
#Volatile private var instance: AppDatabase? = null
val file = File("${Environment.getExternalStorageDirectory()}/appdata/pla/assignment-file/test.db")
Log.d("App Database", "Is valid file? - ${file.isFile}") // true
fun getInstance(context Context) = instance ?: synchronized(this) {
instance ?: Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "MyDb")
.createFromFile(File("path/to/my/test.db"))
.allowMainThreadQueries()
.build().also { instance = it }
}
abstract fun getPlanInfoDao(): PlanInfoDao
}
PlanInfoDao
#Dao
interface PlanInfoDao {
#Query("SELECT * FROM PlanInfo")
fun getPlanInfo(): List<PlanInfo>
}
PlanInfo
#Entity
data class PlanInfo (
#PrimaryKey
#ColumnInfo(name = "Facility_Nbr")
val facilityNbr: String
)
#Query("SELECT * FROM PlanInfo")
It returns a list of PlanInfo
Change return type to List<PlanInfo>
#Query("SELECT * FROM PlanInfo")
fun getPlanInfo(): List<PlanInfo>
Or you might wanna rewrite your query like below.
#Query("SELECT * FROM PlanInfo where Lifecycle_ID= :lifeCycleId")
fun getPlanInfo(lifeCycleId: String): PlanInfo
EDIT
In doubt, you make sure that there is data in that table, try inserting a row successfully before fetching in your code. Make sure its there.

SimpleJdbcInsert equivalent for update

I am using Spring's SimpleJdbcInsert class to create entities - eg:
final SimpleJdbcInsert insert = new SimpleJdbcInsert(dataSource).withTableName("abc");
insert.execute(new BeanPropertySqlParameterSource(abc));
Is there some equivalent of this class for doing updates? As an example, something like the below would be a convenient interface, assuming we are dealing with a single column primary key:
final SimpleJdbcUpdate update = new SimpleJdbcUpdate(dataSource).withTableName("abc").withIdColumn("abcId");
update.execute(new BeanPropertySqlParameterSource(abc));
Does Spring provide this functionality out-of-the-box somewhere?
Thanks
Jay
For any future readers - I came up with a convenience function using reflection;
Works for simple pojos:
public void dao_update(NamedParameterJdbcTemplate database, String table, Object pojo, String[] keys) {
StringBuilder sqlBuilder = new StringBuilder("UPDATE ");
sqlBuilder.append(table);
sqlBuilder.append(" SET ");
boolean first = true;
for (Field field : pojo.getClass().getDeclaredFields()) {
if (!first) {
sqlBuilder.append(",");
}
first = false;
sqlBuilder.append(field.getName());
sqlBuilder.append(" = :");
sqlBuilder.append(field.getName());
}
first = true;
for (String key : keys) {
if (first) {
sqlBuilder.append(" WHERE ");
} else {
sqlBuilder.append(" AND ");
}
first = false;
sqlBuilder.append(key);
sqlBuilder.append("= :");
sqlBuilder.append(key);
}
database.getJdbcOperations().update(sqlBuilder.toString(), new BeanPropertySqlParameterSource(pojo));
}
Example usage:
dao_update(database, "employee", my_employee, "id");
Generates:
UPDATE employee SET id = :id, name = :name, salary = :salary WHERE id = :id
There is an issue in the Spring JIRA about the lack of a SimpleJdbcUpdate class: https://jira.springsource.org/browse/SPR-4691. You might want to upvote it there.
You have to use JdbcTemplate
See: 13.2.1.1 Examples of JdbcTemplate class usage
E.X:
this.jdbcTemplate.update(
"update t_actor set = ? where id = ?",
"Banjo", 5276L);
You can get more similar effect by using SimpleJdbcTemplate instead of JdbcTemplate and by extending SimpleJdbcDaoSupport all DB operations can be put in one DAO class:
import java.util.List;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;
import org.springframework.stereotype.Repository;
#Repository
public class BankDaoImpl extends SimpleJdbcDaoSupport implements BankDao {
#Autowired
public BankDaoImpl(#Qualifier("dataSource") DataSource dataSource) {
setDataSource(dataSource);
}
#Override
public void insert(Bank bank) {
String sql = "INSERT INTO BANK (id, oib, short_name, name, street, town, postal_code, homepage_url, last_change) VALUES (NEXT VALUE FOR bank_seq, :oib, :shortName, :name, :street, :town, :postalCode, :homepageUrl, CURRENT_TIMESTAMP)";
SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(
bank);
getSimpleJdbcTemplate().update(sql, parameterSource);
}
#Override
public void update(Bank bank) {
String sql = "UPDATE BANK SET oib=:oib, short_name=:shortName, name=:name, street=:street, town=:town, postal_code=:postalCode, homepage_url=:homepageUrl, last_change=CURRENT_TIMESTAMP WHERE id=:id";
SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(
bank);
getSimpleJdbcTemplate().update(sql, parameterSource);
}
#Override
public void delete(String id) {
String sql = "DELETE FROM BANK WHERE id=:id";
getSimpleJdbcTemplate().update(sql,
new MapSqlParameterSource("id", id));
}
#Override
public Bank findById(String id) {
String sql = "select b.ID, b.OIB, b.SHORT_NAME, b.NAME, b.STREET, b.TOWN, b.POSTAL_CODE, b.HOMEPAGE_URL, b.LAST_CHANGE, CASE WHEN count(f.id) = 0 THEN 0 ELSE 1 END AS ready " +
"from BANK WHERE b.ID = :id";
return getSimpleJdbcTemplate().queryForObject(sql,
BeanPropertyRowMapper.newInstance(Bank.class),
new MapSqlParameterSource("id", id));
}
}
The easy way to do this is:(source)
public void setName(int id, String name) {
this.jdbcTemplate.update("update mytable set name = ? where id = ?",
new Object[] {name, new Integer(id)});
}

Resources