I'm trying to use the new Architecture components, but when I try to run, I get :
"Error:(375, 24) error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such table: posts)"
The following are my classes.
**ENTITY : **
#Entity
public static class Post {
#PrimaryKey
private String id;
#ColumnInfo(name = "data")
private String data;
public String getId() {
return id;
}
public void setData(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setId(String id) {
this.id = id;
}
}
DAO :
#Dao
public interface PostDao {
#Query("SELECT * FROM posts")
LiveData<List<Post>> getAll();
#Insert
void insertAll(Post... posts);
#Insert
void insert(Post post);
#Delete
void delete(Post post);
}
The database :
#Database(entities = {Post.class}, version = 1)
public static abstract class AppDatabase extends RoomDatabase {
public abstract PostDao postDao();
}
By default, Room uses the class name as the database table name. If you want the table to have a different name, set the tableName property of the #Entity annotation, as shown in the following code snippet:
https://developer.android.com/topic/libraries/architecture/room.html
It seems you assumed it would pluralize the class on its own.
So, either use SELECT * FROM Post
or do
#Entity(tableName = "posts")
class Post {
...
}
Related
I am working with the Spring Boot Jpa Data Structure.
I have after successful test runs without a database been able to run my code flawlessly. After having hooked up my Spring Boot Application to a MySQL database and saving values into it, I run into the following issue:
Upon retrieving the data from database after restarting my application the List with the #ElementCollection is empty. I have checked the database and the data is present within the database, all other data is also retrieved without error. The application produces no error other than a Null Pointer which can be traced back to the value of the list being null.
Here is the code which is failing:
#Entity
public class Entity extends SuperEntity {
#ElementCollection
#LazyCollection(LazyCollectionOption.FALSE)
private List<String> flags;
public Entity() {
super();
this.flags = new LinkedList<>();
}
public Entity(List<String> flags) {
super();
this.flags = flags;
}
public Entity(#NotNull FormEntity formEntity) {
super();
this.flags = formEntity.getFlags();
}
public List<String> getFlags() {
return flags;
}
public void setFlags(List<String> flags) {
this.flags = flags;
}
}
#Entity
public abstract class SuperEntity {
protected #Id UUID id = UUID.randomUUID();
public SuperEntity() {}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
}
Any help is greatly appreciated and any additional materials needed from my end will be provided.
I was reading this link about Spring Data JPA and it got me curious: Instead of using #Query annotation, can you create a query and then use it as a param to the method?
More like this:
#Repository
public interface MyRepository extends CrudRepository<MyClass, Integer>
{
void doSomething(Query query);
}
(BTW, I know I could implement a fragment repository and solve my problem, but I'm curious)
you could not create an implementation class, instead of that you can write interface methods like this:
#Entity
public class Part {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long id;
#Column(unique = true)
private String partId;
public Part() {
}
public Part(String partId) {
this.partId = partId;
}
public String getPartId() {
return partId;
}
public void setPartId(String partId) {
this.partId = partId;
}
public Set<Card> getCards() {
return cards;
}
}
public interface PartRepository extends CrudRepository<Part, Long> {
public Optional<Part> findByPartId(String partId);
public List<Part> findAllByPartId(String partId);
}
Spring automatically convert these lines to SQL in background, you should don't care about that.
You can find some details here: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods
Based on my research we have two way for getting related data from two or more tables.
For example if we have 2 tables like below:
#Entity
public class User {
#PrimaryKey public long userId;
public String name;
public int age;
}
#Entity
public class Library {
#PrimaryKey public long libraryId;
public long userOwnerId;
}
If we want to load all data we have two options:
1. #Embedded and #Relation
By adding this class:
public class UserAndLibrary {
#Embedded public User user;
#Relation(
parentColumn = "userId",
entityColumn = "userOwnerId"
)
public Library library;
}
And add DAO method:
#Transaction
#Query("SELECT * FROM User")
public List<UserAndLibrary> getUsersAndLibraries();
More information in Android Documentation
2. #DatabaseView
#DatabaseView("SELECT user.id, user.name, user.age, " +
"library.libraryId FROM user " +
"INNER JOIN library ON user.userId = library.libraryId)
public class UserAndLibrary {
public long userId;
public String name;
public int age;
public long libraryId;
}
and a associating
#Database(entities = {User.class, Library.class},
views = {UserAndLibrary.class},
version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
What is the difference between two options?
JAVA SPRING :I am exploring JPA and am not sure of optimized way to design db and using save() of repository to save entity data right away into DB. Specifically, I have a basic class viz. Movie -
package com.kurshit.moviesmgr.vo;
import java.util.List;
public class Movie {
long movieId;
String title;
String yearOfRelease;
List<String> genere;
public Movie(long movieId, String title, String yearOfRelease, List<String> genere) {
super();
this.movieId = movieId;
this.title = title;
this.yearOfRelease = yearOfRelease;
this.genere = genere;
}
public Movie() {
// TODO Auto-generated constructor stub
}
public long getMovieId() {
return movieId;
}
public void setMovieId(long movieId) {
this.movieId = movieId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getYearOfRelease() {
return yearOfRelease;
}
public void setYearOfRelease(String yearOfRelease) {
this.yearOfRelease = yearOfRelease;
}
public List<String> getGenere() {
return genere;
}
public void setGenere(List<String> genere) {
this.genere = genere;
}
}
Each movie has list of Genere - List- it falls under, like - Action, Comedy, etc.
I am trying to create an interface that extends JpaRepository and use the inbuilt save method to save the Movie Data into DB.
I am not sure about how I should design my DB - As in, Questions like -
1. Shall I create two different tables for Movie and Genere wherein Movie table references to Genere ?
2. Shall I create just onw table and store all Genere's list as a single CSV in one column ?
3. Can I use repository's save() right away to save and map this data into respective tables.
Would really appreciate if someone can share any sources or sample code to refer or can offer any help.
Thanks much!
First of all, you should search look up #Entity annotation so that you can tell your ORM to create the necesary table for that entity.
Secondly, you need to ask yourself, how this application will work. It would be best in my opinion to create a genre entity as well, linked to Movie through a #ManyToMany relationship.
Try looking over the simple entity example here
https://spring.io/guides/gs/accessing-data-jpa/
First variant - with 'genre' as enum (if your genre is a fixed list):
#Data // it's Lombok annotation: https://projectlombok.org/features/Data
#NoArgsConstructor
#Entity
public class Movie implements Serializable {
#Id #GeneratedValue
private Integer id;
private String title;
private Integer yearOfRelease;
#ElementCollection
#Enumerated(EnumType.STRING)
#Column(name = "genre")
private List<Genre> genres;
public Movie(String title, Integer yearOfRelease, List<Genre> genres) {
this.title = title;
this.yearOfRelease = yearOfRelease;
this.genres = genres;
}
}
public enum Genre {
ACTION, COMEDY, ...;
}
public interface MovieRepo extends JpaRepository<Movie, Integer> {
}
In this case you create your movie like this:
Movie movie = new Movie("Title", 2000, Arrays.asList(ACTION, COMEDY));
movieRepo.save(movie);
Second variant - 'genre' as independent entity:
#Data
#NoArgsConstructor
#Entity
public class Movie implements Serializable {
// the same as previous one...
#ManyToMany
private List<Genre> genres;
}
#Data
#NoArgsConstructor
#Entity
public class Genre implements Serializable {
#Id private String name;
public Genre(String name) {
this.name = name
}
}
public interface MovieRepo extends JpaRepository<Movie, Integer> {
}
public interface GenreRepo extends JpaRepository<Genre, String> {
}
In this case you first create genres:
List<Genre> genres = genreRepo.saveAll(Arrays.asList(
new Genre("Action"),
new Genre("Comedy"),
));
Then create movie:
Movie movie = new Movie("Title", 2000, genres);
movieRepo.save(movie);
More info to read: Hibernate ORM User Guide - Collections
I'm having this error when trying to compile the project:
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
java.lang.IllegalArgumentException: intcannot be converted to an Element
And this warning:
Warning:Supported source version 'RELEASE_7' from annotation processor 'android.arch.persistence.room.RoomProcessor' less than -source '1.8'
These are my database related classes:
#Entity(tableName = "users")
public class SerializedUser {
#PrimaryKey(autoGenerate = true)
private int id;
#ColumnInfo(name = "first_name")
private String firstName;
#ColumnInfo(name = "last_name")
private String lastName;
#ColumnInfo(name = "username")
private String username;
public SerializedUser(int id, String firstName, String lastName, String username) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.username = username;
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getUsername() {
return username;
}
}
#android.arch.persistence.room.Database(entities = {SerializedUser.class}, version = 4)
public abstract class Database extends RoomDatabase {
public abstract UserDao userDao();
private static final String DATABASE_NAME = "weather";
// For Singleton instantiation
private static final Object LOCK = new Object();
private static volatile Database i;
public static Database init(Context context) {
if (i == null) {
synchronized (LOCK) {
if (i == null) {
i = Room.databaseBuilder(context.getApplicationContext(),
Database.class, Database.DATABASE_NAME)
.fallbackToDestructiveMigration().build();
}
}
}
return i;
}
public static boolean isInited(){
return i != null;
}
public static Database getInstance(){
if(i == null)
throw new NullPointerException("Database.getInstance called when Database not initialized");
return i;
}
}
#Dao
public abstract class UserDao {
Converters converters;
public void inject(Converters converters) {
this.converters = converters;
}
#Insert(onConflict = REPLACE)
public abstract void saveNow(SerializedUser user);
#Delete
public abstract void deleteNow(int id);
#Query("DELETE FROM users")
public abstract void deleteAllNow();
#Query("SELECT * FROM users")
public abstract List<SerializedUser> getAllNow();
#Query("SELECT * FROM users ORDER BY last_name ASC")
public abstract LivePagedListProvider<Integer, SerializedUser> usersByLastName();
}
So the error happens when it tries to implement the database classes? That id on SerializedUser is not the problem, I have commented it out, the problem was still the same. Tried to clean and rebuild the project and restarted Android Studio (invalidate and restart).
remove
#Delete
public abstract void deleteNow(int id);
from your Dao it will work
#Delete annotation marks a method in a Dao annotated class as a
delete method. The implementation of the method will delete its
parameters from the database.
All of the parameters of the Delete method must either be classes annotated with Entity or collections/array of it.
Read here for extra information.
So in your case you pass a parameter with int type which violates the aforementioned rule. That is why you are getting that error.
In order to resolve this issue, you should either exclude deleteNow method or just pass any parameter that does not violates the rule that was mentioned above.
Error:Execution failed for task ':app:compileDebugJavaWithJavac'. java.lang.IllegalArgumentException: intcannot be converted to an Element
Basically, this problem arises not only by the #Delete query, but by all the Room's CRUD annotations (#Insert, #Delete, #Update) except #Query.
All of the parameters of these CRUD annotated methods must either be classes annotated with Entity or collections/array of it.
So we can't pass primitive or other than these.