Entity class do not work in room database - kotlin

following error appears:
Entity class must be annotated with #Entity - androidx.room.Entityerror: Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). - androidx.room.Entityerror: An entity must have at least 1 field annotated with #PrimaryKey - androidx.room.Entityerror: [SQLITE_ERROR] SQL error or missing database (near ")": syntax error) - androidx.room.EntityH:\Apps2021\app\build\tmp\kapt3\stubs\debug\de\tetzisoft\danza\data\DAO.java:17: error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such table: geburtstag)
Entity looks like this
#Entity(tableName = "geburtstag")
data class Bday(
#PrimaryKey(autoGenerate = true)
var id : Int,
#ColumnInfo(name="Name")
var name : String,
#ColumnInfo(name="Birthday")
var birth : String
)

The issue would appear to be that you do not have the Bday class defined in the entities in the class that is annotated with #Database.
e.g. you appear to have :-
#Database(entities = [],version = 1)
abstract class TheDatabase: RoomDatabase() {
abstract fun getDao(): Dao
}
This produces the results you have show e.g.
E:\AndroidStudioApps\SO67560510Geburtstag\app\build\tmp\kapt3\stubs\debug\a\a\so67560510geburtstag\TheDatabase.java:7: error: #Database annotation must specify list of entities
public abstract class TheDatabase extends androidx.room.RoomDatabase {
^error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such table: geburtstag) - a.a.so67560510geburtstag.Dao.getAll()error: Not sure how to convert a Cursor to this method's return type (java.util.List<a.a.so67560510geburtstag.Bday>). - a.a.so67560510geburtstag.Dao.getAll()error: a.a.so67560510geburtstag.Dao is part of a.a.so67560510geburtstag.TheDatabase but this entity is not in the database. Maybe you forgot to add a.a.so67560510geburtstag.Bday to the entities section of the #Database? - a.a.so67560510geburtstag.Dao.insert(a.a.so67560510geburtstag.Bday)
Whilst :-
#Database(entities = [Bday::class],version = 1)
abstract class TheDatabase: RoomDatabase() {
abstract fun getDao(): Dao
}
compiles successfully.
note the change from entities=[] to entities = [Bday::class]

You should set default values for constructor args. In this case kotlin will generate no arg constructor. Try this
#Entity(tableName = "geburtstag")
data class Bday(
#PrimaryKey(autoGenerate = true)
var id : Int = 0,
#ColumnInfo(name="Name")
var name : String = "",
#ColumnInfo(name="Birthday")
var birth : String = ""
)

Related

Returning one of multiple class types from a data class

I have scenario where in I have a "Lookup Table" class that holds getters and setters for multiple class types. As I'm interfacing with a database, I need to provide a way to provide a result boolean and then the class instance which was requested.
For example. Say I have an AssetStatus, StockItemStatus and NominalCode class. I would have to write the following data class for each:
data class LookupResult(
val wasSuccessful: Boolean = false,
val resultClass: AssetStatus? = null,
)
// or
data class LookupResult(
val wasSuccessful: Boolean = false,
val resultClass: StockItemStatus? = null,
)
// or
data class LookupResult(
val wasSuccessful: Boolean = false,
val resultClass: NominalCode? = null,
)
Ideally I don't want to have to repeat myself so I was wondering if I could write one data class (or normal class?) which is able to return one of my multiple Lookup classes?
Initially I thought it would have needed to be Any but after looking into this, that might not be the best case for what I want.
So is there a way of sticking to writing once but not repeating? Or is it something I have to do?
Edit:-
All of my class types would have the following structure (note: I'm using Spring Boot as back end) :
#Entity
#Table(name = "lookup_asset_status")
data class AssetStatus(
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "asset_status_id")
val id: Long? = null,
#Column(name = "asset_status_name")
val name: String = "",
)
...
// Repeat for each entity type
...
If I understand correctly, you want something like this:
data class LookupResult<T>(
val wasSuccessful: Boolean = false,
val resultClass: T? = null,
)
Each of the classes would be written as LookupResult<AssetStatus>, LookupResult<StockItemStatus> and LookupResult<NominalCode>.
If your method needs to be able to return any of those three classes, then it should be declared to return LookupResult<*>. Note that you can only access the members of Any when you access the resultClass of a LookupResult<*>, because you don't know which exact look up result it is.

InvalidDataAccessApiUsageException - Parameter value did not match expected type

I need to get all users with a specific role from a database. For this I need to use JPA.
All roles are stored in a special set:
UserAccount.kt
#ManyToMany(cascade = [(CascadeType.MERGE)])
#JoinTable(
name = "user_authorities",
joinColumns = [JoinColumn(name = "user_id", referencedColumnName = "id")],
inverseJoinColumns = [JoinColumn(name = "authority_id", referencedColumnName = "id")]
)
var authoritySet: MutableSet<Authority> = hashSetOf()
I want to do it like this:
UserAccountService.kt
override fun getAllUsersByAuthorityName(name: String): List<UserAccountDto> {
return userAccountRepository.findUsersByAuthoritySet(mutableSetOf(authorityService.findAuthorityByAuthorityName(name))).map { it.toDto() }
}
UserAccountRepository.kt
#Query("select u from UserAccount u where u.authoritySet = ?1")
fun findUserAccountByAuthoritySet(authoritySet: MutableSet<Authority>): List<UserAccount>
But when calling these methods in tests, it gives an error:
Parameter value [Authority(id=1, authority='ROLE_ADMIN')] did not match expected type [java.util.Set (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [Authority(id=1, authority='ROLE_ADMIN')] did not match expected type [java.util.Set (n/a)]
Tell me how you can properly organize the search for users?
Can you show sites with examples of such requests?
First, I started using the JPA functionality and added the "In" particle to the method name in the repository.
In the second, I removed the #Query annotation
Third, I revisited my tests, and it turned out that I added roles after the saved users, and therefore my changes were not committed to the database. I fixed it.
Problem solved

Kotlin SpringMVC - JpaRepository generating invalid update query

I'm quite new to Spring MVC, and I'm having problems getting a simple entity update to work.
My data class looks like this...
#Entity
#Table(uniqueConstraints=[UniqueConstraint(columnNames=["name_search"])])
data class ArticleType(
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
val name : String = "",
val order: Int? = null,
var name_search : String = ""
)
The repository looks like so...
interface ArticleTypeRepository : JpaRepository<ArticleType, Long> {
fun findFirstById(id: Long) : ArticleType?
fun findAllByOrderByOrderAsc(): List<ArticleType>
fun findByName(name: String): ArticleType?
}
I'm trying to update the name_search column like so...
val article_type:ArticleType? = articleTypeRepository.findFirstById(1234)
if (article_type !== null) {
article_type.name_search = "abc"
articleTypeRepository.save(article_type)
}
This results in the following error...
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order=99 where id=1234' at line 1
I'm assuming this means the binding isn't working correctly, and it's missing the "name_search" binding, or missing the quotes or something. I've turned on logging, and I can see the following...
org.hibernate.SQL : update article_type set name=?, name_search=?, order=? where id=?
Then it lists the binding parameters "o.h.type.descriptor.sql.BasicBinder", which all appear to be correct.
I'm not sure what's going wrong, or where I need to start to try to fix it.
This is a legacy system I've inherited, and I don't fully understand it. If there is some extra information I need to provide here, please let me know.

Analogue of #Formula annotation from JPA for Spring data neo4j?

I'd like to calculate some properties of my domain objects at DB level using neo4j and return the read-only results. In JPA one can achieve this via #Formula annotation over field of domain object entity:
#Formula("(select avg(f.rating) from Feedback f where f.offer_id = offer_id)")
private Double rating;
What should one do to achieve the same behavior in Spring data neo4j? I wrote a Cypher query, but don't know where to use it.
A similar outcome can be achieved using #QueryResult
Create a class with fields to hold return data.
Annotate it with #QueryResult
Example: (in Kotlin, which is what I had on hand)
#QueryResult
open class Principal constructor(applicationToken: String,
profileId: String,
stageName: String,
showMeLaterDays: Float,
roles: Array<Role>)
{
var applicationToken: String
var profileId: String
var stageName: String
var showMeLaterDays: Float
#Convert(RoleArrayAttributeConverter::class)
var roles: Array<Role>
init
{
this.applicationToken = applicationToken
this.profileId = profileId
this.stageName = stageName
this.showMeLaterDays = showMeLaterDays
this.roles = roles
}
//Provide a default constructor for OGM
constructor() : this(applicationToken = "", profileId = "", stageName = "", showMeLaterDays = 0f,
roles = emptyArray())
}
Then use it with a repository as follows:
#Query("MATCH (n:CandidateProfile {applicationToken: {0} })
RETURN n.id as profileId, n.applicationToken as applicationToken, n.stageName as stageName, n.showMeLaterDays as showMeLaterDays, n.roles as roles;")
fun findByApplicationToken(token: String): Principal?
Note the way that node properties are returned to correspond with the class field names.
The same can be done with function results.

HibernateException: Errors in named query

When running a particular unit-test, I am getting the exception:
Caused by: org.hibernate.HibernateException: Errors in named queries: UPDATE_NEXT_FIRE_TIME
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:437)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1385)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:891)
... 44 more
for the named query defined here:
#Entity(name="fireTime")
#Table(name="qrtz_triggers")
#NamedQueries({
#NamedQuery(
name="UPDATE_NEXT_FIRE_TIME",
query= "update fireTime t set t.next_fire_time = :epochTime where t.trigger_name = 'CalculationTrigger'")
})
public class JpaFireTimeUpdaterImpl implements FireTimeUpdater {
#Id
#Column(name="next_fire_time", insertable=true, updatable=true)
private long epochTime;
public JpaFireTimeUpdaterImpl() {}
public JpaFireTimeUpdaterImpl(final long epochTime) {
this.epochTime = epochTime;
}
#Override
public long getEpochTime() {
return this.epochTime;
}
public void setEpochTime(final long epochTime) {
this.epochTime = epochTime;
}
}
After debugging as deep as I could, I've found that the exception occurs in w.statement(hqlAst) in QueryTranslatorImpl:
private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException {
HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole );
AST hqlAst = parser.getAST();
// Transform the tree.
w.statement( hqlAst );
if ( AST_LOG.isDebugEnabled() ) {
ASTPrinter printer = new ASTPrinter( SqlTokenTypes.class );
AST_LOG.debug( printer.showAsString( w.getAST(), "--- SQL AST ---" ) );
}
w.getParseErrorHandler().throwQueryException();
return w;
}
Is there something wrong with my query or annotations?
NamedQuery should be written with JPQL, but query seems to mix both names of persistent attributes and names of database columns. Names of database columns cannot be used in JPQL.
In this case instead of next_fire_time name of the persistent attribute epochTime should be used. Also trigger_name looks more like name of the database column than name of the persistent attribute, but it seems not to be mapped in your current class at all. After it is mapped, query is as follows:
update fireTime t set t.epochTime = :epochTime
where t.triggerName = 'CalculationTrigger'
If SQL query is preferred, then #NamedNativeQuery should be used instead.
As a side note, JPA 2.0 specification doesn't encourage changing primary key:
The application must not change the value of the primary key[10]. The
behavior is undefined if this occurs.[11]
In general entities are not aware of changed made via JPQL queries. That gets especially interesting when trying to refresh entity that does not exist anymore (because primary key was changed).
Additionally naming is little bit confusing:
Name of the class looks more like name of the service class
than name of the entity.
Starting name of the entity with lower
case letter is rather rare style.
Name of the entity, name of the
table and name of the class do not match too well.