Implementing Content Provider: compound primary key - android

I'm implementing my own Content Provider because I'm gonna synchronize my database with a server. My data is stored in a SQLiteDatabase, and some of my tables have a compound primary key (2 columns, each one a foreign key to another table).
I just started working with Content Providers and I don't know much how they work, but as I could see googling a bit I need to define the name of the tables and their primary key:
uriMatcher.addURI(PROVIDER_NAME, "books", BOOKS);
uriMatcher.addURI(PROVIDER_NAME, "books/#", BOOK_ID);
As I understand it, if I use the URI .../books/1 it would access the Book with primary key "1". The thing is, does it work with a compund primary key? If it does, how would the URI be?
Thank you!

I'm implementing my own Content Provider because I'm gonna synchronize my database with a server.
You do not need to use a ContentProvider to synchronize a database with a server.
The thing is, does it work with a compund primary key?
Not readily. Quoting the docs:
Table data should always have a "primary key" column that the provider maintains as a unique numeric value for each row.
You could to add a separate column (typically named _id) that you will use for the ContentProvider as the primary key. If you use an AUTOINCREMENT column, you will not ever have to assign a value yourself, meaning that you can ignore this column in pretty much all respects except where ContentProvider wants an instance Uri.
You are welcome to attempt to avoid this, and use a Uri that looks like content://your.authority.goes.here/table/key1/key2 or something like that. However, it will not work with CursorAdapter and various other places in the framework may assume the numeric ID pattern.

Related

Get/Return the autogenerated id (as primary key) generated by Android Room database

For an android room interface, I want to get the autogenerated id (as primary key of a record just inserted), so that I can put it in the object without executing a select after insert, where the select might return the wrong record if there is no other unique attribute, or set of attributes for those record types.
For example, for 2 people having the same name being inserted into the same table. You might say generate a composite key to make a unique set. However that might involve the addition of new fields that are otherwise not required.
I've seen various links, including those below. Some mention that it is the row id that is returned if the insert method is declared to return integer (or long), and succeeds.
However it is my understanding that the row id cannot be assumed to be the same as the primary key. (Refer Rowid after Insert in Room).
I cannot comment on any posts because I don't have enough reputation points.
I appreciate any comments regarding what might be a good/typical approach to this problem.
These are the posts I have looked upon:
Android Room - Get the id of new inserted row with auto-generate
https://developer.android.com/training/data-storage/room/accessing-data
https://commonsware.com/AndroidArch/previews/the-dao-of-entities
Late answer just for anyone seeing this question in the future
from SQLite docs it says :
The PRIMARY KEY of a rowid table (if there is one) is usually not the
true primary key for the table, in the sense that it is not the unique
key used by the underlying B-tree storage engine. The exception to
this rule is when the rowid table declares an INTEGER PRIMARY KEY. In
the exception, the INTEGER PRIMARY KEY becomes an alias for the rowid.
therefore it's correct to assume that the rowId returned by insert query is the same as the autoincremented-primary-key

What is the best practise in choosing a table's primary key

I used to create a column called 'id' which is auto incremented in any table I create. While in some cases I found that this column is useless while another column like 'citizen_ssn' is a better candidate to be the primary key.
So, what is the best practice in choosing the table's primary key ?
Should I use what will fit the need or create the auto-increamented column or another opinion ?
Any attribute which is unique and not null can be used as a primary key. Generally id is used as a primary key by many developers. But there's no such rule except mentioned above.
What is a Primary Key?
Apart from Auto-Incrementing it, a primary key is used to Identify a row. As every row is unique, so is the Primary key. Two or more rows with a column number n can have the same value, let's say "Australia" but the column with Primary Key constraint will have the unique value.
So, it's not important to use the id column as a primary key.
One can use phoneNumber as a PK too.
Depends on the usage.
I hope I've made myself clear.
In Realm there is no real reason to have an auto-increment primary key. (although if your server returns primary key info, then it's useful to know that you're referring to the same object).
In SQLite (or any relational database) the reason you need them is that that is the only way you can link two objects together (through JOINs) - for example, a many-many relationship is done with a Join Table that contains the primary key of both linked tables as a foreign key.
In Realm, you can link objects together as a field like private OtherObject otherObject;, and many relation as private RealmList<OtherObject> otherObjects. So you don't need primary key to create relationship.
What you might need them for in Realm is if you want to use insertOrUpdate() method to update an existing object in Realm by its primary key, overwriting it with an unmanaged object. You can also edit objects by calling the managed object's setters, so this is not entirely necessary.

Does sqlite "insert or replace" work with AUTOINCREMENT primary key?

I have a database in which i have created one table with name "SectionDetails".
In this table i have set "id" as a primary key with AUTOINCREMENT property.And i am inserting my data into this table.
However, i came to the scenario where i need to check if record i am inserting is already present or not(if record is present then replace it with same values or skip it,And if record is not present then insert new one ).
But when i tried to insert record with same column values, it increases the primary key and insert the same row again instead of replacing.
So, my question is-
Does sqlite "insert or replace" works with AUTOINCREMENT primary key?
I am using following query:
insert or replace into SectionDetails(Name,Month,Title,Url)values('Deepak',"August","None","www.dd619.com")
here column "id" is not appearing because its a primary key with AUTOINCREMENT property.
You will need to add some unique constraints to your other columns to make this work and even then you will have your IDs change.
insert or replace is really an insert with on conflict replace conflict resolution strategy. That is, when the insert would violate some constraint, all conflicting rows are first deleted and the insert takes place only then. The autoincrement mechanism will then generate a new ID value for you.
For more information: http://www.sqlite.org/lang_conflict.html
Short answer: no it does not.
The "insert or replace" only works well when you also specify the primary key. With the autoincrement in a setup that you describe, this cannot work.
Probably the quickest way to do that is by creating a custom insert/update method for your use case.

SQLite CREATE table with an alias for ROWID

Looking at this answer I was trying to work out how to actually create a table with a column that is just an alias for ROWID. I would like to do this as some android classes require a unique column named '_id' but i dont want that col to be a PRIMARY KEY. I cant use AUTO_INCREMENT on the col that not a PK either, so I would just like _id to be an alias. I know I could do that in the query but thats not practical for my situation. Any pointers? Is this even possible?
Thanks :)
EDIT: really i just want to be able to have my own PK but also have an id field for CursorAdapters to work correctly etc
EDIT: Looking at Do i have to use _ID as a SQlite primary key? and does it have to be an INT? (Android Dev) it suggests to do it in the query if my PK is a number type also, but what if its a TEXT col that im using for my PK? (sort of thinking aloud here) - I guess i could copy CursorAdaptor and just getString instead of a long for the _id col (plus, pass the name of the col to use as the PK in to cursor adapter, get rid of _id!) OR just add a alias for the ROWID as _id in the SELECT, feels a bit hacky though...
You may have a primary key that is completely independent of SQLite's built-in rowid.
Every row of every SQLite table has a 64-bit signed integer key that uniquely identifies the row within its table. This integer is usually called the "rowid". The rowid value can be accessed using one of the special case-independent names "rowid", "oid", or "rowid" in place of a column name.
You may formulate your query so that the built-in rowid is called _id for the benefit of the CursorAdaptor by prepending the hidden rowid column to your results:
select _rowid_ as _id, ...
The rowid is unique, but need not be the primary key. You can make the primary key anything you like in the CREATE TABLE statement.
TBH, I don't think that this is really feasible. You are required to have that kind of PK column (even though with a lot of hacking you could create some kind of workaround).
I would rather suggest to have the _id column as a technical PK and have an additional column as logical PK i.e. just a freely defined column with a unique constraint. Your program logic should then be able to simply use the logical PK for all operations. Of course this would require you to use custom queries for find operations etc. but that is usually more fitting anyways.
hth..

data duplication in sqlite with android app

i am getting information from user in sqlite database.
But when i insert same record which is already in database it is added again.
how i can stop duplication of record in sqlite. I am developing this in android.
I am using mobile number as primary key. still it add that record in database.
Please suggest me appropriate solutions.
Thanks in advanced.
Be aware of the limitations of REPLACE or INSERT OR REPLACE as these will overwrite any custom data your app user has added to these rows in the database - it is not as advanced as UPSERT in other SQL databases.
As mentioned in a previous post you really need to identify what the primary key could be and use this information to either update old data or to remove an old row before inserting the fresh one.
If this is not possible then you could always DELETE FROM my_table or DROP my_table before running the insertions so that there will be no duplicates. This will (for better or worse) also make sure that data that is missing from new imports is not left lying around in your app.
make sure you have set your phone number as Primary Key at the time you created the table.
for example:
String query = "CREATE TABLE IF NOT EXISTS PhoneBook ("+
"TelNum VARCHAR(100) PRIMARY KEY NOT NULL,"+
"Address TEXT);";
db.execSQL(query);
and in case you want to enforce foreign keys defined in your table then call the following method before doing anything in your database
db.execSQL("PRAGMA foreign_keys = ON;"); //enforcing FK
Use REPLACE INTO keyword:
REPLACE INTO my_table (pk_id, col1) VALUES (5, '123');
This automatically identifies the primary key and finds a matching row to update, inserting a new one if none is found.

Categories

Resources