Android Ormlite mapping to Sqlite - android

I can't find the Ormlite DataType mapping for Android to Sqlite. I've found OrmLite SQL Data Types but the Sqlite column is blank. Anyone know were I can find them?
I need them to update my database schema ie:
meetingDao.executeRaw("ALTER TABLE meeting ADD closed ????");

I'm not exactly sure what you are asking but Sqlite is a type-less database. Everything is stored as a string basically with certain functions allowing numerical, time, etc. calculations at runtime on those strings.
To quote from the Sqlite data-type docs:
SQLite is "typeless". This means that you can store any kind of data you want in any column of any table, regardless of the declared datatype of that column. (See the one exception to this rule in section 2.0 below.) This behavior is a feature, not a bug. A database is suppose to store and retrieve data and it should not matter to the database what format that data is in. The strong typing system found in most other SQL engines and codified in the SQL language spec is a misfeature - it is an example of the implementation showing through into the interface. SQLite seeks to overcome this misfeature by allowing you to store any kind of data into any kind of column and by allowing flexibility in the specification of datatypes.
In the SQL Data Types page you mentioned, the Sqlite column is blank because it uses the base data columns without the need to override them. Even if I changed the base types for a class, Sqlite will not override any of the types because, again, it is a type-less database.

Actually, the mapping table linked by the original question: OrmLite SQL Data Types shows the correct types that ORMLite is using, although it only shows differences for each database from the Base Database column. For example a Java long is created as a column with the BIGINT type.
While SQLite3 doesn't have types, it has the concept of type affinities which ORMLite uses when creating the table.
You should probably include the types in database upgrades as well, or you'll get a different table definition when ORMLite is automatically creating the table form scratch and when you upgrade.

Related

Is there a way to generate SQLite file from iOS platform, which is compatible with Android Room database library?

We have an Android app, which is using read/ write data using Android Room database library, and then download/ upload to cloud storage.
Now, we are developing an iOS app, which is suppose able to read/ write the data.
There is no issue for our iOS app to read SQLite file written by Android Room database, because we are the one who define database schema.
However, there are issue, for iOS app to write an Android Room database library compatible SQLite file. We notice Android Room database library is expecting the following 3 additional tables.
CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT);
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE sqlite_sequence(name,seq);
The sample data contain in the 3 additional tables are as follow.
INSERT INTO "main"."room_master_table" ("id", "identity_hash") VALUES ('42', '5471e2f102feee2750d42986836b0c42');
INSERT INTO "main"."android_metadata" ("locale") VALUES ('en_US');
INSERT INTO "main"."sqlite_sequence" ("name", "seq") VALUES ('plain_note', '62');
INSERT INTO "main"."sqlite_sequence" ("name", "seq") VALUES ('attachment', '6');
INSERT INTO "main"."sqlite_sequence" ("name", "seq") VALUES ('tab_info', '5');
I think I am able to generate data for android_metadata & sqlite_sequence manually.
But, I am clueless in generating data for room_master_table.
I tested a SQLite file without room_master_table, it will cause the following error during reading via Android Room.
Caused by: java.lang.IllegalStateException: Room cannot verify the
data integrity. Looks like you've changed schema but forgot to update
the version number. You can simply fix this by increasing the version
number.
I was wondering, is there a way to generate SQLite file from iOS platform, which is compatible with Android Room database library? Or, it is simply not possible?
In short don't try to create the said tables, they are all system tables you should let them be created accordingly.
android_metadata just stores the locale and is created by the android SQLiteOpenHelper.
room_master_table stores a hash of the schema, if the hash doesn't match then you get Looks like you've changed schema but forgot to update the version number.. The hash is created at compile time.
sqlite_sequence exists if the AUTOINCREMENT keyword is used in a PRIMARY KEY definition. There is rarely any need to use AUTOINCREMENT. It is recommended to not use AUTOINCREMENT (Room's autogenerate = true). The table hold's a row per table that has AUTOINCREMENT. It stores the highest ever used rowid value. When a new row is inserted instead of just using the highest rowid to determine the next ( max(rowid) + 1), it instead uses the greater of the max(rowid) and the stored max ever allocated value and then adds 1. Thus it has to access the sqlite_sequence table to get the value and thus unless there is a need to always have a rowid greater than any ever allocated it is a waste.
If you use an SQLite database for both, and the IOS doesn't have sqlite_sequence then you should not have autogenerate coded anywhere in the #PrimaryKey annotation, as Room will then hit the Expected .... Found .... errors. As room is very particular about the schema.
I was wondering, is there a way to generate SQLite file from iOS platform, which is compatible with Android Room database library? Or, it is simply not possible?
Yes it is possible. In short don't create any of the tables, let Room create them. Then (assuming that both schemas are similar enough (data wise) have the same columns and column order). You can then load the Room tables from the SQLite file along the lines of
`INSERT INTO room_table_? SELECT * FROM ios_table_?;`
When and how frequently you do this will change exactly how you get to the stage when you can do the copy. If the schemas are identical and it's a one of then you could perhaps utilise the .createFromFile or if the schemas are close .createFromFile where you can modify the schema accordingly (if so then you might find this useful).

Room - How to explicitly create all tables first time via migration?

I want to explicitly create all DB tables in an empty database myself via migration.
How can I do this?
Room always creates initial tables itself using entity classes. This is an unreliable approach. I can't control schema and have to rely on Room.
Room always creates initial tables itself using entity classes. This is an unreliable approach.
It is not unreliable in fact the opposite. However, what should be understood is that Room is about storing and retrieving objects when the underlying database manager, SQLite, has no concept of objects, just tables with columns. As such Room has to be able to create the objects (Entities) from the columns in a row or rows and hence rules that must be met. If met then Room is quite reliable.
I can't control schema and have to rely on Room.
You can and do by the way of coding the entities. However, the rules come with limitations or perhaps more correctly proper/formal use of SQLite. So you have control over the schema but it must adhere to Room's rules/limitations.
An example is column types.
SQLite has a very flexible approach to column types. In that virtually anything can be a accepted as a column type.
Room however, must know how to store/extract the object (entity). As such Room restricts column types to INTEGER, TEXT, REAL or BLOB (the 4 types that SQLite supports). Room does not support the catch-all NUMERIC type and it does not support SQLite's conversion of other column types to a type via SQLite's rule for determining type affinity.
Room is NEVER going to accept a column defined as timestamp DATE as an example as DATE is not one of INTEGER, TEXT, REAL or BLOB (in SQLite DATE resolves to a type affinity of NUMERIC, the catch all).
I want to explicitly create all DB tables in an empty database myself via migration. How can I do this?
In short do one of the following:
Follow Room's rules when defining the schema,
Be smart and let Room do the work (as explained below), or
Use native SQLite rather than Room.
The smart way, as you must have Entities, is to create the Entities and the class annotated with #Database and then compile. Doing so will generate code with the expected schema. The generated code is in the generated java, visible via the Android View in Android Studio. It is in the class that is the name of the class annotated with #Database suffixed with _Impl. In the createAllTables method are the create table SQL statements that Room uses if and when Room creates the tables. This is what Room expects and will adhere to the rules.
You can then use the SQL created by Room as the basis for creating or modifying tables.
You can do many things in the Migration. The creation of new tables, if new tables are introduced, would be a requirement as the Migration is passed an unchanged database. It is the job of the Migration to alter the database and thus create new tables if that is required according to the Entities defined in the #Database annotation.

How do I read-write foreign keys using ActiveAndroid?

In ActiveAndroid, I can build relationships by directly referencing the POJO. For instance, if House had many Windows, this would be fairly straightforward.
Rather than using this direct reference, is there a way to manually set the foreign key and still be able to ActiveAndroid Select later on?
The reason for this is that we are performing data syncing from the server to Android. The data comes in JSON, but rather than being nested the data already comes with foreign keys. I would like to set the foreign keys to our data models without diving too deep into SQLite code.
UPDATE to #ssh's answer:
I am not trying to dynamically change the database structure. Rather, I would like to manually set the foreign key of my models. My assumption is that ActiveAndroid wraps around foreign key queries to directly access other objects that are defined as attributes. Is there a way to access that foreign key table directly?
Thanks for the current answer - I'll look more into setting that value in the foreign key column directly using SQLite.
ActiveAndroid does not support a mechanism for dynamically changing database structure. It is inconvenient, but this is true.
If you want to change your database structure the only way to do that is execute SQLite query.
It can be possible via reflection, using dynamically adding annotation, but Java is not supported this.
For change column name you can use this thread.

Is Parse.com an appropriate service for backup/sync with SQLite in Android?

The example apps and documentation I've seen so far seems to use Parse as the primary (if not only) storage solution for the app, which is great in some situations.
I'm looking to integrate Parse with an existing application of mine on Android, which uses multiple SQLite tables in a single database.
Are there any examples which show usage of Parse, where local storage (i.e. the SQLite DBs) is the primary storage, and data is only sync'd between Parse and local storage if there are newer changes which need updating/committing?
For my database, I have two tables, Tasks and Dates. Tasks is formed of:
_id (a unique integer key for this table)
item (a String describing the task)
desc (a String with a longer description - may be null)
parent (an integer indicating the _id of this task's parent)
and Date:
_id (a unique integer key for this table)
item_id (a foreign key which corresponds to _id in Tasks) date (a date stored in long
format)
In this instance, would I store each row as a separate ParseObject? Having different classes for Task and Date, and I could link Dates with their Task parents? Is this the recommended way?
--
Edit: I received a reply from an engineer at Parse who said that it's possible (to sync with a local SQLite DB), but that it's not supported, and didn't comment on the method I proposed - specifically mapping rows to ParseObjects.
I have been thinking on similar lines but there is not adapter or library that implements the sync. So, you would have to implement it from scratch. Seeing as your schema is pretty straight-forward, it shouldn't be too difficult.
Is the solution is appropriate: in your scenario parse.com would act as any other REST service that would provide data, so I don't see any problems.
Actually, now there is a simple library for Parse <=> sqlite integration.
Check out https://github.com/ntoskrnl/DataSync

Android: ContentProvider for each table / handling one-to-many relationships

When using a content provider for SQLite database access
Is it better practice to have a content provider for each table or to use one for all tables?
How to handle one-to-many relationships when creating new records?
A ContentProvider is not a database
A ContentProvider is a way to publicly (or semi-publicly) access data as content. This may be done in a number of ways, via file access, SQLite or even web access. A ContentProvider in and of itself is not a database, but you can program a database for it. You may also have multiple ContentProviders accessing the same database, but distributing different levels of access, or the same content in different ways according to the requestor.
What you are really asking is not a ContentProvider question, but a database question "How to handle relationships in an SQLite database" because the ContentProvider doesn't use any database code unless you tell it to via an SQLiteOpenHelper and other similar classes. So, you simply have to program your database access correctly and your SQLite database will work as desired.
A database is a database
In the old days, databases were simply flat files where each table was often its own entity to allow for growth. Now, with DBMS, there is very little reason to ever do that. SQLite is just like any other database platform in this regard and can house as many tables as you have space to hold them.
SQLite
There are certain features that SQLite handles well, some that it handles - but not well, and some that it does not handle at all. Relationships are one of those things that were left out of some versions of Android's SQLite, because it shipped without foreign key support. This was a highly requested feature and it was added in SQLite 3.6.22 which didn't ship until Android 2.2. There are still many reported bugs with it, however, in its earliest incarnations.
Android pre 2.2
Thankfully being SQL compliant and a simple DBMS (not RDBMS at this time), there are some easy ways to work around this, after all, a foreign key is just a field in another table.
You can enforce database INSERT and UPDATE statements by creating CONSTRAINTs when you use your CREATE TABLE statement.
You can query the other table for the appropriate _id to get your foreign key.
You can query your source table with any appropriate SELECT statement using an INNER JOIN, thus enforcing a pseudo-relationship.
Since Android's version of SQLite does not enforce relationships directly, if you wanted to CASCADE ON DELETE you would have to do it manually. But this can be done via another simple SQL statement. I have essentially written my own library to enforce these kinds of relationships, as it all must be done manually. I must say, however, the efficiency of SQLite and SQL as a whole makes this very quick and easy.
In essence, the process for any enforced relationship goes as follows:
In a query that requires a foreign key, use a JOIN.
In an INSERT use a CONSTRAINT on the foreign key field of NOT NULL
In an UPDATE on the primary key field that is a foreign key in another TABLE, run a second UPDATE on the related TABLE that has the foreign key. (CASCADE UPDATE)
For a DELETE with the same parameters, do another DELETE with the where being foreign_key = _id (make sure you get the _id before you DELETE the row, first).
Android 2.2+
Foreign keys is supported, but is off by default. First you have to turn them on:
db.execSQL("PRAGMA foreign_keys=ON;");
Next you have to create the relationship TRIGGER. This is done when you create the TABLE, rather than a separate TRIGGER statement. See below:
// Added at the end of CREATE TABLE statement in the MANY table
FOREIGN KEY(foreign_key_name) REFERENCES one_table_name(primary_key_name)
For further information on SQLite and its capabilities, check out SQLite official site. This is important as you don't have all of the JOINs that you do in other RDBMS. For specific information on the SQLite classes in Android, read the documentation.
As for first question: you don't need to create content provider for every table. You can use in with multiple tables, but the complexity of provider increased with each table.
A Content Provider is roughly equivalent to the concept of a database. You'd have multiple tables in a database, so having multiple tables in your content provider makes perfect sense.
One to many relationships can be handled just like in any other database. Use references and foreign keys like you would with any other database. You can use things like CASCADE ON DELETE to make sure records are deleted when the records they reference in other tables are also deleted.

Categories

Resources