Room with Multi user Database in Single android App - android

Can we have a multiple databases in single android App using Room? I want to create a new database for every single user. If user1 logged in I have to create a Database for that user like UserDB1, If any new account added I have to create a another Database for that user like UserDb2. If account switch happened between that accounts I should access the user specific Database.How can i achieve that?

I did that like below,
private static AppDatabase buildDatabase(final Context appContext, int userId) {
return Room.databaseBuilder(appContext, AppDatabase.class, DATABASE_NAME + "_" + userId)
.addCallback(new Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
}
})
.build();
}
I understand your requirement totally. There are 3 ways,
(Let's say only need a table userTable, but actually we have more.)
Create a database for each login user. (You asked, I also used it)
Only a database, but create a table for each user, such as userTable_1. (It seems that Room can't support it )
Only a database and a table for all users, so we have to add a extra column user_id to the table; if we have 20 table, we have to add "user_id" to all 20 tables. (We did it in the backend development at the most time; but in the case, I really do NOT prefer to this one)

Maybe you could but this approach is wrong for several reasons. You dont make separate databases for users you make tables with relations to each other, each row is an entry for a user.
Some tables have a one-to-many relationship like a table that holds order numbers. One user may have many orders. Or the table may have a one-to-one relationship like a user profile. What it breaks down to is, each user has a unique entry and ID, that ID would relate to other tables with their data. You use the ID for the logged in person to get their data.
Beyond that, you really shouldnt be storing other peoples data in your app, what is the situation where you feel multiple people will be using the same phone for the app? The ideal situation is to have a cloud based server/database that you get your data from so only the current users data is retrieved.
The final reason you dont do multiple databases is that if you want to add a new field you would have to update every DB created instead of just one.

Related

SQLite in Android - How to generate User IDs with date and sequential number per day

I currently have an app where I store user data in a SQLite database, and one of my fields is a User ID. I would like to add an option to auto-generate User IDs in an mmddyyXXX format, where XXX is a sequential number per user that resets every day.
Does anyone know how I would approach this? I looked at some of the other similar questions, but they don't seem to be helpful.
This is not complicated at all. If your'e similar with SQLite in android just take the date and the userId using a SELECT and generate that string yourself.
If the XXX is not the userId just save another table containing 'tokens' for users. every userId would have a 'token'.
Every new day just change the contents of this table.
I believe you could use a TRIGGER that will generate the userid when a row is inserted.
The following may suit :-
CREATE TRIGGER IF NOT EXISTS newuserid AFTER INSERT ON users
BEGIN
UPDATE users SET userid = strftime('%m%d',date('now'))||substr(strftime('%Y',date('now')),3)||
(
SELECT CAST(substr('000',1,3-length(count()+1)) AS TEXT)||CAST((count()+1) AS TEXT)
FROM USERS
WHERE substr(userid,1,6) = strftime('%m%d',date('now'))||substr(strftime('%Y',date('now')),3)
)
WHERE userid IS NULL;
END;
The trigger is named newuserid
userid is the column for the auto-generated id. The above relies upon it being NULL so it cannot be a PRIMARY INDEX.
There is no reliance upon other columns.
Testing
Starting with an empty table :-
Inserting 4 rows using INSERT INTO users VALUES(null,'This is a new user'); results in :-
To check for another date the rows are adjusted from 041018??? to 040918??? as per :-
4 more rows are inserted using INSERT INTO users VALUES(null,'This is a new user');, resulting in :-
Note this answer isn't intended to be fail-safe but rather the basis of the concept for the answer.

How to set up databases (tables) in Android to perform searches between them

EDIT
I have learned that I might not need multiple databases, but multiple tables within that database.
What I have now
I am building an app that is going to deal with recipes. Currently, I have sort of a locker where you can add your items that you want in that locker. That could be, for example, a pack of minced beef or a loaf of bread or what not. I let the user add this in the app, depending on what they have in their locker/fridge/freezer. I am doing this, using SQLiteDatabase. Everything works the way I want it do, but now, I want to add some more features.
What I want to achieve
Okay, so in my app, I have a search button. When a user wants to search, he should be able to type an ingredient (like minced beef) and then receive results of recipes containing minced beef. He should also be able to search for a recipe and then get to that recipe, or recipes similar to the one he typed in.
Scenario 1. A user searches for an ingredient.
What should happen The user should get results on all recipes containg that special ingredient. When the user finds a recipe that he likes, he should be able to click on it and the app should show what ingredients he have at home and what ingredients he needs to purchase.
Scenario 2. A user searches or a recipe
What should happen. The user gets result on the recipes that matches his search. If he clicks on one, the ingredients that he has should show (as in Scenario 1) and the ones he needs to purchase should also show, also as in scenario 1.
The question
How should I, as efficiently (in terms of execution time) as possible set up the databases to be able to display information from different databases with one search. I found this http://www.databaseanswers.org/data_models/recipes/index.htm, from what I'm guessing that I will need multiple databases.
I do not need help to code the setting up phase, but merely how the structure of databases should be designed.
Thanks in advance.
You don’t need to have multiple databases to store objects of your application model. You may want to consider using the following (or something similar) domain model classes for your app and have the corresponding tables in the database:
public class Recipe {
int id;
String name;
String source; // Mom, A friend's name, A website url, a magazine name, etc.
Date lastUpdated; // When the recipe was added/updated
ArrayList<Ingredient> ingredients; // A list of ingredients used by this recipe
}
public class Ingredient {
int id;
String name;
String preferredSources; // a store name, a friend's name :), etc.
ArrayList<Recipe> recipes; // A list of recipes which use this ingredient
}
public class RecipeIngredient { // Join class for many-to-many relationship
int recipeId;
int ingredientId;
}
public class Inventory {
int ingredientId;
int location; // locker, fridge, freezer, etc.
float quantity; // in weight, count, etc.
Date lastUpdated; // When the last replenishment was done
}
Since you have a many-to-many relationship between Recipe and Ingredient objects, I am suggesting creating a join class RecipeIngredient. The Inventory class is for the ingredients you currently have at home.
Your searches may happen against Recipe and Ingredient classes (tables). Once you get the corresponding ingredientId(s), you may search your Inventory for the availability of those ingredients at home.
After shopping for Ingredient items, you should update the Inventory class (table). Also, after an ingredient is used up, you should update its Inventory quantity.
To simplify the development effort including automatic database schema (tables) creation for your app, you may consider using an ORM like JDXA. Here are some code snippets for handling many-to-many relationships with JDXA.

Android Content Provider SQLite Junction Tables

I'm implementing a Content Provider, which is backed by a fairly complex SQLite DB schema. The database has a few junction tables and I'm unsure whether they should be visible to the user of the Content Provider or not.
The parent tables are exposed via the Contract, each one has its own content URI, etc. Now, when inserting data via ContentResolver#applyBatch() method, I create ContentProviderOperation per each table's content URI. So far everything is clear. But my problem is, how should the junction tables be populated, as they don't have their own content URIs?
To illustrate this, here's an example. I have 2 "parent" tables, Movies and Actors. The relationship between them is many-to-many and therefore I have a junction table called MoviesActors.
To insert at one batch I do the following:
List<ContentProviderOperation> operations = new ArrayList<>;
// movie
operations.add(ContentProviderOperation.newInsert(Contract.Movie.ContentUri).withValue("movie_id", "23asd2kwe0231123sa").build());
// actor
operations.add(ContentProviderOperation.newInsert(Contract.Actor.ContentUri).withValue("actor_id", "89asd02kjlwe081231a").build());
getContentResolver().applyBatch(authority, operations);
The junction table MoviesActors should be inserted with a row containing movie_id and actor_id. How do I take care of the junction table in this situation?
The only thing, which comes to my mind is extend the Contract to have content URI pointing to the junction tables and add another ContentProviderOperation, since otherwise, how do you communicate movie_id and actor_id to ContentProvider#applyBatch()?
I rather not expose the junction table to the user of the ContentProvider, but I might be wrong here... perhaps that's how it should be done on Android?
I've searched this topic for days already and haven't found an answer to that.
Any help would be greatly appreciated.
Bonus question:
Is it necessary to expose every single table via the Contract? For instance, when having child tables in one-to-many relationship. I'm specifically referring to Insert/Update/Delete since I know with Query I can simply do a join, but maybe I'm wrong also here.
Thanks a lot!
NOTE: I'm not interested in 3rd party library solutions.
I think you're tackling the problem from the wrong end. You're trying to design an interface to match your database structure, but the interface should come first.
In the first place, the interface should meet all the requirements of your ContentProvider client. If your ContentProvider client needs access to the junction table you'll have to expose it (in some way, see below), otherwise you don't have to. A good interface hides the actual implementation details, so the ContentProvider client doesn't need to care about whether the ContentProvider is backed by an SQLite database, by a bunch of in-memory maps or even a web-service.
Also, you should not think of a ContentProvider just as an interface to a database and the Contract as the database schema. A ContentProvider is much more versatile and powerful than that. The major difference is that ContentProviders are addressed by URIs whereas in SQL you just have table names. In contrast to a table name, a URI has a structure. URIs have a path that identifies the object (or directory of objects) that you want to operate on. Also you can add query parameters to a URI to modify the behavior of an operation. In this respect a ContentProvider can be designed much like a RESTful service.
See below for a concrete (but incomplete) example of a Contract of a simple movie database. This is basically how one would design a RESTful web-service, except for one thing: Just like in your code, movie-id and actor-id are provided by the caller. A real RESTful service would create and assign these automatically and return them to the caller. A ContentProvider can only return long IDs when inserting new objects.
Insert a new movie
insert on /movies/
Values: {"movie_id": <movie-id>, "title": <movie-title>, "year": ...}
Insert a new actor
insert on /actors/
Values: {"actor_id": <actor-id>, "name": <actor-name>, "gender": ...}
Add an existing actor to a movie
insert on /movies/movie-id/actors/
Values: {"actor_id": <actor-id>}
Add an existing movie to an actor:
insert on /actors/actor-id/movies/
Values: {"movie_id": <movie-id>}
Optional: add a new actor directly to a movie:
insert on /movies/movie-id/actors/
Values: {"actor_id": <actor-id>, "name": <actor-name>, "gender": ... }
If no actor with the given id exists, this operation will create the new actor and link it to the movie in a single step. If an actor with this ID already exists an exception would be thrown.
The same could be done the other way round, adding a new movie to an actor.
Delete an actor from a movie
delete on /movies/movie-id/actors/actor-id
or
delete on /actors/actors-id/movies/movie-id
Get all movies
query on /movies/
Get a specific movie
query on /movies/movie-id
Get all actors playing in a specific movie
query on /movies/movie-id/actors/
Get all movies a specific actor has played in
query on /actors/actor-id/movies/
The optional query selection statement can be used to filter the result. To get movies from the last 10 years a specific actor has played in, you would add the selection movies_year>=2005 to the last query.
By using a contract like this you wouldn't expose the junction table, instead you provide a REST-like interface to your database.
The job of the ContentProvider is to map these operations onto the database or any other back-end.

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).

Multiple toMany relationships to a single table

I'm new to greenDAO and I'm working on writing the DaoGenerator. One issue that I've run into is that I have a user table and a wallpost table. I would like to be able to have two columns in the wallpost table that are toMany relations to the user table (the wall owner and the posting user) they may or may not be the same user, but so far it doesn't look like it is possible to have two toMany relations that point to a single table in the same table.
Is there a better way to do this/a way to make this possible? I'm hoping to be able to load the wall posts and fetch the wall owner and posting user by calling .getOwner() and .getPoster().
Thanks
You must set names for the relations. Have a look at the (just improved) section called Relation Names and multiple Relations of the documentation on relations. It comes with an example:
Property pictureIdProperty = user.addLongProperty("pictureId").getProperty();
Property thumbnailIdProperty = user.addLongProperty("thumbnailId").getProperty();
user.addToOne(picture, pictureIdProperty);
user.addToOne(picture, thumbnailIdProperty, "thumbnail");

Categories

Resources