ROOM, SQLite and class hierarchy - android

So, this is my problem. I've been googling for some time now and no other question on this topic seems to approach what bugs me.
In my Android application, I have a class hierarchy, a list of tourist attractions. Every TouristAttraction has, among others, a boolean attribute that specifies whether that attraction is among user's "favorite" attractions.
However, when I insert a specific type of a tourist attraction, say a Monument, Room insert puts both inherited and specific attributes in one table and not in superclass table, so when I want to get a list of all "favorite" attractions, I have to combine results of select queries for every subclass.
Also, when I want to mark something as favorite, this way I first have to see what type of tourist attraction it is, and then get specific DAO... which seems kinda ugly. Is there a way to, when I insert a new row in Monument table, data from inherited fields gets inserted into superclass table?
This problem happens every time I need to collect data that every tourist attraction has, like location etc.

Im not familiar with android-room. But from a sqlite point of view I would structure your TouristAttactions in a separate table without any favorite flags. And then have a second table with the mapping between the user's favorite and attractions.
CREATE TABLE tabTouristAttrations (ID INTEGER AUTOINCREMENT, Name TEXT, ...);
CREATE TABLE mapFavoritesUser (AttrID INTEGER NOT NULL, UserID INTEGER NOT NULL, PRIMARY KEY (AttrID, UserID)
cheers
Andy

Related

Designing you SQLite DB in anticipation of your future code?

Here is my situation:
A senior member/boss in a company using my app will be able to assign "tasks" to his/her employees. A "task" may contain many "sub-tasks". Right now my only requirement is to make a "task" and a "sub_task" table in my database like this:
CREATE TABLE `tasks` (
`id` INTEGER NOT NULL,
`title` TEXT NOT NULL,
`description` TEXT NOT NULL,
PRIMARY KEY(id)
)
and sub_tasks:
CREATE TABLE `sub_tasks` (
`id` INTEGER NOT NULL,
`title` TEXT NOT NULL,
`description` TEXT NOT NULL,
`tasks_id` INTEGER NOT NULL,
PRIMARY KEY(id)
FOREIGN KEY(tasks_id) REFERENCES tasks(id)
)
As you can see I use tasks_id in sub_tasks table as a foreign key referenced to id in tasks table. Right now it serves my requirement well. But in future when I will create an Employee class, the situation will be like this: A Senior member will/can assign many tasks to a single employee and every task may/may not contain many sub_tasks. How can you design you database in anticipation of this requirement so that it will not break down my code?
Can tasks be assigned to multiple employees, or will they be assigned to only one employee at a time?
If it's the former, you'll need another table, "employee_tasks" or something of the sort. I won't go into this much because I feel it's the least likely option, but basically you create unique employee/task pairs and you can ensure that multiple employees have completed the same task.
If it's the latter, all you'll need is a new column in the task table for "employee_id." That employee is now in charge of that task. How you choose to get all the information is up to your personal preference and how many db hits you're comfortable with, but I'd personally select all tasks for a given employee, and then for each task I'd find its subtasks. If you want to make fewer db hits you can find all tasks, then find all subtasks through a join, and then match the tasks in memory. Those are the two "easy" ways I know of doing it, though I wouldn't be surprised if there's something a bit more clever out there.

Saving a changing amount of Values in a SQL-Database

i am really stuck at this point of my android app development.
What i need is a way to save a changing amount of int or string-values (in a sql database). Yet im not even sure if this is the right approach, but let me explain:
In the app i am currently working on, you are able to create certain "events". Users should be able to apply for such events.
I have an external database with 2 tables:
first one for users - every user has a unique ID
second one for events - every event has a unique ID
I need each event to know what users applied for it. And i need each user to know what events they applied for.
I was thinking to save the Event-IDs in the User-Table and vice versa.
I just dont know how to do that since the amount of applicants/ID's can change. Is there a way to save Arrays in the database which can easily be edited (e.g. +/- one ID) and read?
Is this even the right way? I am very happy for any advise!
Thanks in advance!
What you seem to want is a many-to-many relationship. A user can be part of many events, and an event can have many users. That requires an additional table though:
Table: User Columns: UserId, Name, ...
Table: Event Columns: EventId, Name, ...
Table: UserEvents Columns: UserId, EventId, ...
In the new table, UserEvents, you would store the UserId's and EventId's like this:
UserEvents
UserId EventId
1 1
2 1
1 2
This means that if you selected UserId 1, the query would return EventId 1 & 2. If you selected EventId 1 the query would return that UserId 1 & 2 would be attending.
This is the standard and recommended way to deal with many-to-many. It's very flexible and can easily be scaled.
You could either use a Compound key (Composite Key) for this table, or create a column specifically as a Primary Key. The code below can be used, and manipulated, to create both your table and Compound/Composite key (I'm guessing on data types).
CREATE TABLE UserEvents
(
[UserId] INT NOT NULL,
[EventId] INT NOT NULL
CONSTRAINT PK_UserEvents PRIMARY KEY NONCLUSTERED ([UserId], [EventId])
)
I would add a third table (e.g. UserEvents) to store which events a user has applied for, along with other relevant attributes (e.g. ApplicationTime, ApplicationStatus). This association would have a foreign key relationship back to the related tables and resolve the many-to-many relationship between users and events.
What you have there is called a "many-to-many" relationship between to tables which can only be resolved by the introduction of a third table between your two tables that stores the associations.
This table would contain the User-ID and the Event-ID as foreign keys (and maybe additional information).

Dynamically creating tables in SQLite with user input in Android

I'm quite new to Android and the SQLite. I'm currently working on an app which requires user to create list of their favourite artists.
I have implemented some charts which already display this artist data. I believe I can easily figure out how to implement adding data to lists.
I was thinking of having two separate tables in SQLite :
Lists (which would store the list names which the user has created)
ChartItems (which would store the chart items and the lists they belong to)
However the Lists table only needs one field in this case "ListName" so I thought it might not be crucial to have a table for this.
Is it possible to dynamically create tables when getting input from a user?
For example : A user creates a list and that value is subsequently used to create a table.
Thanks.
You don't want to be creating new tables on the fly. Your proposal for two tables is fine. The list table should have at least two fields - an integer field called id or _id which is the primary key, and a text field for the list name. The Chartitems table will have a field (listid) which holds the id of the list to which it belongs. This means a chartitem can belong to only one list, and adding a chartitem to a list is achieved by setting the listid field in its record. This is a one-to-many relationship.
If you want to have a single chartitem in more than one list, then you need a many-to-many relationship, which is implemented by having a third table (links). This table will have one field mapping to a list (listid), and one field mapping to a chartitem (itemid.) To add a chartitem to a list, you create the appropriate link entry in the links table. In this case the chartitem table does not need the listid field.
I suggest reading up some more on relationships in databases to clarify these concepts. One principle I strongly suggest following is to have every table contain a field called id which is the primary key for that table, and use that for all references from other tables. In the long run this works much better than using other fields (like name) in relationships.

Dynamic Tables in Android SQLite

My question involves databases - The scenario is this:
I have an app that tracks when people borrow items. I have an existing table which tracks who they are, what they have borrowed and so on. What I would like to do is create a separate table to track what the person has borrowed, their contact info, if they returned it, etc.
My idea to do this would be to create a Dynamic table in SQL that would hold the records for 1 person, ie
John Smith
DVD; July 12, 2012; Returned in good condition; etc
As I'm still learning, I wanted to know if:
This is possible, feasible or if there is a smarter way of going about it.
Your answer depends on your scenario;
If you are only interested with "who" borrowed "what" (currently) and not "when" except last occurance, and you are assuming there are always only 1 copy of an item, then you can use one to one relation as:
CREATE TABLE Person
(
PersonId int IDENTITY(1,1) NOT NULL,
Name nvarchar(30) NOT NULL,
Surname nvarchar(30) NOT NULL,
BorrowItemId int NULL FOREIGN KEY REFERENCES Item UNIQUE,
BorrowDate datetime NULL,
ReturnDate datetime NULL,
ReturnCondition nvarchar(50) NULL,
CONSTRAINT PK_Person PRIMARY KEY CLUSTERED (PersonId ASC),
)
CREATE TABLE Item
(
ItemId int IDENTITY(1,1) NOT NULL,
ItemDescription nvarchar(50) NOT NULL,
CONSTRAINT [PK_Item] PRIMARY KEY CLUSTERED (ItemId ASC)
)
If you have multiple copies of each item you should remove the UNIQUE key on BorrowItemId changing relation to one to many. In case;
To see the items borrowed and returned with person information:
SELECT PersonId, Name, Surname, ItemDescription, ReturnDate, ReturnCondition
FROM Person INNER JOIN Item
ON BorrowItemId = ItemId
WHERE BorrowItemId IS NOT NULL
AND ReturnDate IS NOT NULL
You can add PersonId filter in WHERE clause to query for specific person
This isn't a good design since you can insert records without date information or you can even have records with date info but no related BorrowItemId. I suggest using many to many and keep historic data (can be handy) or overwrite using update each time the person borrows a new item
Their contact information could be linked into the table which tracks who they are.
If you have not created a table yet for the returns then I suggest you reference the borrowing table's ID and set in the borrowing table a flag to say this item has been returned.
I am not too sure why you would want to create a new table to collate all the information. If you want to get all the information together then I suggest using the SQL keywrod JOIN when preparing statements. If you really want to store the information later on in a table you can but it will just be duplicates in your database.
A tutorial on the different types of joins you can do : http://www.w3schools.com/sql/sql_join.asp
It is definitely possible to do as you describe. It really isn't a very good strategy, though. Your new table is, exactly, equivalent to an additional column in the existing table that tags the row as belonging to a specific individual.

Displaying data in a ListView when each object is located on more than one row in a Cursor

In my application I have a sqlite database that looks like this:
CREATE TABLE notes (_id integer primary key,
content text);
CREATE TABLE tags (_id integer primary key,
name text,
noteid integer,
foreign key(noteid) references notes(_id));
I'm storing text that can have some tags associated with it. Now I want to show this text and the tags in a ListView. However I can't figure out how to do this with a SimpleCursorAdapter. Is it even possible? My data might look like this:
sqlite> select * from notes;
1|foo bar baz
sqlite> select * from tags;
1|x|1
2|y|1
The query to get all notes and the data it returns looks like this:
sqlite> select notes._id, notes.content, tags.name from notes, tags where notes._id = tags.noteid;
1|foo bar baz|x
1|foo bar baz|y
Now, if I want to bind this data to the ListView in some way, how to do it? I would be happy if each row int the ListView contained two lines, one line with the content and one line with all the tags. Am I correct in guessing that the SimpleCursorAdapter won't help me here? What should I do instead?
SimpleCursorAdapter alone can't help you here.
If your goal is that you want one row to be one note + all its tags, you can try overriding bindView() in SimpleCursorAdapter and pouring in the tags that way. That would imply that you have already built up some sort of HashMap of note->tags and therefore can quickly determine the tags to go in the row.
To build up the HashMap, you have two choices that I see:
Build them on the fly by looking up the note in the HashMap, then doing a query to get the tags for that note if they're not found, caching them in the HashMap for later reuse (e.g., scrolling). The catch here is that you're doing a bunch of little queries (bad) and doing them on the main application thread while the user is scrolling (really bad).
Do one big query using an IN clause to get all tags for all notes, and convert the resulting Cursor into a fully-populated HashMap. Then, your per-row lookups will all succeed. This works well if you only have a modest number of rows; otherwise, this query may take longer than the user has patience for.
If your schema is flexible, you might consider whether you are better served with some amount of denormalization, such as having the tags in a single column of the notes table via a comma-delimited list or something. Even if that complicates write operations (e.g., putting tags in two places), if your reads greatly outnumber your writes, it may be worth it.

Categories

Resources