Xamarin + sqlite: Trouble reading database - android

I am opening a database file, and running select * query and no objects are found. I have:
Created a DB in DB Browser for SQLite, stored the db file in common project, as well as assets/resources for Droid/iOS with proper Build Action (AndroidAsset/BundleResource)
Created interface in common code and DatabaseService in Droid:
public SQLiteConnection CreateConnection()
{
var sqliteFilename = "StepsDatabase.db";
string documentsDirectoryPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var path = Path.Combine(documentsDirectoryPath, sqliteFilename);
var conn = new SQLite.SQLiteConnection(path);
//conn.CreateTable<Step>();
//conn.CreateTable<SuperStep>();
return conn;
}
(I have tried with and without the .CreateTable as I saw that was a possible solution from another question)
Created C# mdoels for both tables in my database
namespace StepsDB
{
[Table("Step")]
public class Step
{
[PrimaryKey, AutoIncrement, Unique, Column("stepID")]
public int stepID
{
get;
set;
}
[NotNull, Column("name")]
public string name
{
get;
set;
}
[NotNull, Column("superStep")]
public int superStep
{
get;
set;
}
[Column("videoLocation")]
public string videoLocation
{
get;
set;
}
[Column("uploader")]
public string uploader
{
get;
set;
}
[Column("uploaderIG")]
public string uploaderIG
{
get;
set;
}
}
}
Created a DatabaseManager that calls CreateConnection() and then a select * query from both tables and empty Lists are created.
Even when I debug and check the "conn" variable, it has TableMappings Count = 0.
PS using sqlite-net-pcl NuGet installed in all projects.
I have been stuck on this for a LONG time and have scoured the internet but no solution that worked for others have worked for me. Please help!
Also this is my first question so if I have done anything wrong please let me know.

I was never properly opening my database asset, only creating an empty file. I now use
var binaryReader = new BinaryReader(Android.App.Application.Context.Assets.Open(sqliteFilename))
to open the asset and write it to the file location I was trying to open originally. Once I create the connection it properly maps to my objects and I have a list to use! :) :)

You can use EF Core to access Sqlite databases easily.
use this command to install EFCore Sqlite package:
Install-Package Microsoft.EntityFrameworkCore.Sqlite
Then you can use EFCore standard functions to create databases at runtime.

Related

Can I create an in-memory database with SqlDelight for running in Android?

I have a SqlDelight database that is working nicely. I create it like this:
Database(AndroidSqliteDriver(Database.Schema, context, DatabaseName)
For unit-tests, I create an in-memory database like this:
Database(JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY).apply {
Database.Schema.create(this)
})
I wanted to do the same for androidTests that run on the emulator or on a physical device, but JdbcSqliteDriver doesn't work in Android, presumably because Android doesn't have that package installed by default.
How do I run an in-memory database in AndroidTest (or in production)?
It turns out if you don't name your database, it creates an in-memory version:
Database(AndroidSqliteDriver(Database.Schema, context, null)
Because AndroidSqliteDriver uses SupportSQLiteOpenHelper.Builder which has this in the documentation:
/**
* #param name Name of the database file, or null for an in-memory database.
* #return This
*/
#NonNull
public Builder name(#Nullable String name) {
mName = name;
return this;
}

Android Room Not Recognizing Column Name From Schema (using an alias for column name)

I am relatively new to Android Development and using its Room persistence library. The problem I am currently facing is the following error:
error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such column: s_abb)
However my table schema (that this column is being referenced by) does contain this column by this name. Here is how I defined my entity in Android
#Entity
public class stops {
#PrimaryKey
#NonNull
#ColumnInfo(name = "s_name")
private String s_name;
#Ignore
#ColumnInfo(name = "s_abb")
private String s_abb;
#Ignore
#ColumnInfo(name = "Comments")
private String Comments;
public String getS_abb() {
return s_abb;
}
public void setS_abb(String s_abb) {
this.s_abb = s_abb;
}
public String getS_name() {
return s_name;
}
public void setS_name(String s_name) {
this.s_name = s_name;
}
public String getComments() {
return Comments;
}
public void setComments(String comments) {
Comments = comments;
}
}
I have tested the query in SQLite Studio and it does return expected data. Here is a screen shot of query written within DAO Interface: Query. I personally think the main problem is that Room may not recognize the aliases I am using with my subqueries and the column names. Am I correct in thinking this? I hope my screenshot helps. I did make sure to add proper spacing between SQL statements, as many solutions here have pointed out. If any of you need me to provide more information, I am happy to oblige! Thank you
As Vladimir Gladun pointed out, the column s_abb that I was querying for was set with an #Ignore annotation over it. Which as Android's documentation on #Ignore annotations states that "Ignores the marked element from Room's processing logic":
https://developer.android.com/reference/android/arch/persistence/room/Ignore.
Which basically means Room disregards it completely.
However this was not the only problem, My method was expecting Entity type values
whereas the SELECT statement from my outermost query was returning String type values. Fixing those two errors solved my problem.

How to use SQLite.Net to create, insert and draw data in Xamarin.Android?

I am new to Xamarin and android development. I am making a timetable app and currently have no idea of how to create a database using sqlite.net. Is there possibly any documentation of all the commands that can be used and a thorough description somewhere? Because all i could find are stuffs related to Java, IOS, and other stuffs.
In my app, i need to create, access, insert, modify and draw links between database, I am unsure of how to do any.
thanks
Using SQLite.nET is very easy in Xamarin Android/iOS/Forms. Simply add a nuget package "sqlite-net" intp your project. This will add two files, SQLIte.cs and SQliteAsync.cs in your root folder. It uses ORM hance its CRUD functions can be used easily.
Here are few links from Xamarin that will help you understand the concepts better.
https://developer.xamarin.com/guides/cross-platform/application_fundamentals/data/part_3_using_sqlite_orm/
https://developer.xamarin.com/recipes/android/data/databases/sqlite/
https://developer.xamarin.com/recipes/ios/data/sqlite/
https://developer.xamarin.com/guides/xamarin-forms/working-with/databases/
https://developer.xamarin.com/recipes/ios/data/sqlite/create_a_database_with_sqlitenet/
EDIT 1:
Include sqlite-net nuget package by Frank Krueger in your application.
Create a file for keeping all Databse related functions. For instance DbOperations.cs
public class DbOperations
{
public string SqLiteDBPath { get; private set; }
public DbOperations()
{
string databasePath = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.Personal), DBConstants.DATABASE_PATH);
_sqLiteDBFilePath = System.IO.Path.Combine(databasePath, DBConstants.DATABASE_NAME);
SqLiteDBPath = databasePath;
System.IO.Directory.CreateDirectory(SqLiteDBPath);
//create database in set path
SQLite.SQLite3.Config(SQLite.SQLite3.ConfigOption.Serialized);
SQLiteConnection sqLiteConnection = new SQLiteConnection(_sqLiteDBFilePath);
sqLiteConnection.Close();
CreateTables();
}
private void CreateTables()
{
SQLiteConnection sqLiteConnection = new SQLiteConnection(_sqLiteDBFilePath);
sqLiteConnection.CreateTable<User>();
sqLiteConnection.Close();
}
}
This snippet will create database and table for object named User in the db.
To perform CRUD operations simply write
SQLiteConnection con = new SQLiteConnection(_sqLiteDBFilePath);
con.Insert(userObject); //Insert
con.Delete(userObject); //Delete
con.DeleteAll<>(); //Delete All rows in table User
con.Update(userObject); //Update
List<User> userList = con.Query<User>("select * from User"); //Select all
Hope this helps you.

Android - XML or SQLite for static data

I am making Android app for practicing driving licence theory tests. I will have about 3000 questions. Question object would have several atributes (text, category, subcategory, answers, group). I will create them and put in app, so data won't ever change. When user chooses category, app would go througt data, look which question meets requirements (that user selected) and put it in list for displaying. What should I use to store data/questions, XML or SQLite? Thanks in advance.
Edit:
I forgot to mentiont that app won't use internet connection. Also, I planned to make simple java app for entering data. I would copy text from government's website (I don't have access to their database and I have to create mine), so I thought to just put question's image url to java program and it would download it and name it automaticaly. Also, when entering new question's text it would tell me if that question already exist before I enter other data. That would save me time, I wouldn't have to save every picture and name it my self. That is what I thought if using XML. Can I do this for JSON or SQLite?
If you do not have to perform complex queries, I would recommend to store your datas in json since very well integrated in android apps using a lib such as GSON or Jackson.
If you don't want to rebuild your app / redeploy on every question changes. You can imagine to have a small webserver (apache, nginx, tomcat) that serves the json file that you will request on loading of the app. So that you will download the questions when your app is online or use the cached one.
XML is a verbose format for such an usage, and does not bring much functions....
To respond to your last question, you can organise your code like that :
/**
* SOF POST http://stackoverflow.com/posts/37078005
* #author Jean-Emmanuel
* #company RIZZE
*/
public class SOF_37078005 {
#Test
public void test() {
QuestionsBean questions = new QuestionsBean();
//fill you questions
QuestionBean b=buildQuestionExemple();
questions.add(b); // success
questions.add(b); //skipped
System.out.println(questions.toJson()); //toJson
}
private QuestionBean buildQuestionExemple() {
QuestionBean b= new QuestionBean();
b.title="What is the size of your boat?";
b.pictures.add("/res/images/boatSize.jpg");
b.order= 1;
return b;
}
public class QuestionsBean{
private List<QuestionBean> list = new ArrayList<QuestionBean>();
public QuestionsBean add(QuestionBean b ){
if(b!=null && b.title!=null){
for(QuestionBean i : list){
if(i.title.compareToIgnoreCase(b.title)==0){
System.out.println("Question "+b.title+" already exists - skipped & not added");
return this;
}
}
System.out.println("Question "+b.title+" added");
list.add(b);
}
else{
System.out.println("Question was null / not added");
}
return this;
}
public String toJson() {
ObjectMapper m = new ObjectMapper();
m.configure(Feature.ALLOW_SINGLE_QUOTES, true);
String j = null;
try {
j= m.writeValueAsString(list);
} catch (JsonProcessingException e) {
e.printStackTrace();
System.out.println("JSON Format error:"+ e.getMessage());
}
return j;
}
}
public class QuestionBean{
private int order;
private String title;
private List<String> pictures= new ArrayList<String>(); //path to picture
private List<String> responseChoice = new ArrayList<String>(); //list of possible choices
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getPictures() {
return pictures;
}
public void setPictures(List<String> pictures) {
this.pictures = pictures;
}
public List<String> getResponseChoice() {
return responseChoice;
}
public void setResponseChoice(List<String> responseChoice) {
this.responseChoice = responseChoice;
}
}
}
CONSOLE OUTPUT
Question What is the size of your boat? added
Question What is the size of your boat? already exists - skipped & not added
[{"order":1,"title":"What is the size of your boat?","pictures":["/res/images/boatSize.jpg"],"responseChoice":[]}]
GIST :
provides you the complete working code I've made for you
https://gist.github.com/jeorfevre/5d8cbf352784042c7a7b4975fc321466
To conclude, what is a good practice to work with JSON is :
1) create a bean in order to build your json (see my example here)
2) build your json and store it in a file for example
3) Using android load your json from the file to the bean (you have it in andrdoid)
4) use the bean to build your form...etc (and not the json text file) :D
I would recommend a database (SQLite) as it provides superior filtering functionality over xml.
Create the db using DB Browser for SQLite
And then use the library SQLiteAssetHelper in the link-
https://github.com/jgilfelt/android-sqlite-asset-helper
Tutorial on how to use -
http://www.javahelps.com/2015/04/import-and-use-external-database-in.html
You can use Paper https://github.com/pilgr/Paper its a fast NoSQL data storage for Android.
SQLite is the best for your system. because you will have to maintain (text, category, subcategory, answers, group) etc. So if you create db and create table for them. That will be easy to manage and you can relationship with each other which is not possible to XML.

SQLite add a list to a table

I am writing a Xamarin Android application using SQLite and am not sure how to add an object to a table where the object has a list.
Here is my model class:
public class TestObject
{
[PrimaryKey]
public int Id { get; set; }
public string name { get; set; }
public DateTime lastUpdate { get; set; }
public List<TestItem> items { get; set; }
}
Here is my code to add an object to a table:
public void InsertObjectToDatabase<T>(string databasePath, T objType)
{
var db = new SQLiteConnection (databasePath);
db.CreateTable(typeof (T));
db.InsertOrReplace (objType);
}
Here is my code to add a TestObject to a table:
TestObject testObject = new TestObject ();
testObject.Id = 1;
testObject.name = "Test Object 1";
testObject.lastUpdate = DateTime.Now;
sQLiteService.InsertObjectToDatabase<TestObject> (filename, testObject);
This is the error that I am getting:
System.NotSupportedException: Don't know about System.Collections.Generic.List`1[LearningSQLite.TestItem]
Is it possible add a list to a SQLite table?
Thanks in advance
Create another table and refer to the parent table with a foreign key. Once you insert the row in parent, insert all the items from the list in the child. Read more here http://www.sqlite.org/foreignkeys.html
If you are using SQLite.Net-PCL you can use the IBlobSerializer interface to store complex types to a BLOB (byte array). Here is a unit test class that provides more info:
https://github.com/oysteinkrog/SQLite.Net-PCL/blob/master/tests/BlobSerializationTest.cs
For the serializer you can either implement your own or use something like JSON serializers to store the data as JSON.
I am using the BLOB interface to use SQLite as key-value pair caching mechanism:
https://github.com/XForms/Xamarin-Forms-Labs/blob/master/src/Xamarin.Forms.Labs/Plugins/Caching/Xamarin.Forms.Labs.Caching.SQLiteNet/SQLiteSimpleCache.cs

Categories

Resources