android ormlite - storing string array - android

I want to persist a class which contain String array.
How to do it in ormlite?
For example,
class A {
int age;
String[] childrenNames = new String[2];
}

First you make the class Serializable.
You can optionally add the table name at the top of the class by annotation.
then for the variables you have to add the database field annotation. In case of the string array you also have to annotate it as a Serializable datatype.
You will get something like this:
#DatabaseTable(tableName = "A")
Class A implements Serializable{
#DatabaseField
int age
#DatabaseField(dataType = DataType.SERIALIZABLE)
String[] childrenNames = new String[2];
}
Also dont forget to create getters and setters for each of the variables.

I want to persist a class which contain String array. How to do it in ormlite? For example,
You could store this as a serialized stream for sure.
However, a better way to do this is to use a ForeignCollection. ORMLite does not do the magic fu that other ORM libraries do to support arrays. Maybe it should. In the meantime, here are the docs on setting up another table for your children-names:
http://ormlite.com/docs/foreign-collection
One table would be for A. Another table would be for the ChildrenName. Each ChildrenName entity would have a foreign-field of A which would show which A each name corresponded to.

#Gray told the better way todo.
#ForeignCollectionField(eager = false)
ForeignCollection orders;
From docs:
In the above example, the #ForeignCollectionField annotation marks that the orders field is a collection of the orders that match the account.
The field type of orders must be either ForeignCollection or Collection – no other collections are supported because they are much heavier with many methods to support.

Related

How to persist particular values taken from multiple pojo classes in a single table into Room Database in Android?

I am making an application where I have to persist data in a database, I have one single table in my project with multiple entity classes. Actually, I have to take some values from each POJO classes and have to store in a single table in the database. I have a class which has some following fields
private List<CurrentWeatherInfoDBModel> currentWeatherInfoDBModel =
new ArrayList<CurrentWeatherInfoDBModel>();
private CurrentWeatherMainDBModel currentWeatherMainDBModel;
private CurrentWeatherWindDBModel currentWeatherWindDBModel;
private CurrentWeatherCloudsDBModel currentWeatherCloudsDBModel;
private long dt;
private CurrentWeatherSysDBModel currentWeatherSysDBModel;
private int id;
private String name;`
now say for example CurrentWeatherMainDBModel is a pojo class containing 2 another fields that has to be stored into that single table. I am using Room as my database. How can I do that?
Extract all data you need to insert into database from their sources into one POJO and make this newly created POJO your entity for ROOM. So, if you need to get any data from your database, you will refer to this newly created POJO since that will be the building block of your database

How to deal with Relational Data in nested 1-to-1 objects in Room (Convert ForeignKey to Object)

Let's say I have an Order and a User Entity that resembles something like this:
User.java:
#Entity
public class User {
#PrimaryKey
public long id;
#NonNull
public String username;
}
Order.java:
#Entity(foreignKeys = #ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "user_id",
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE),
indices = #Index("user_id"))
public class Order {
#PrimaryKey
public long id;
public String description;
#ColumnInfo(name = "user_id")
public long userId;
#Ignore
private User user;
}
So this way, I have an Order with a User inside it, on the database I am only saving this relation with the user id as a Foreign Key and not the object itself (it's #Ignored), so everything is nice and relational and can be expanded to be used with other types in several different ways and queries and etc.
Now, the question is, how do I get an Order with the User object automatically populated by Room inside it?
If I use #Embedded, then Order and User will live on the same table, which is not good for relational separation of the types. I could return them both together with a JOIN but still this only works for data types that have different names (maybe they both have a column named "description"?), besides, inserting an Order with a User inside it wont be simple with a JOIN. #Relation only works for one-to-many and it needs a List, which is not my case.
I thought that maybe a #TypeConverter would be the best option here, converting between long and User, but this also is tricky. The #TypeConverter would need a reference to the DAO so it could query the User and the #TypeConverter is a static method, invoked by Room, so passing the DAO can be tricky and lead to many code smells, besides this extra query for each User would trigger multiple searches that won't be in the same #Transaction.
I am new to Room, but I bet there's a proper way to fix this, to use Room with relational types as it was intended to be used, I just can't find out how to make this work simply and nicely nor I can find it in any documentations.
Now, the question is, how do I get an Order with the User object automatically populated by Room inside it?
I think there is not an out of box solution for this.
IMHO, the entity model (i.e. the Order mapping a FK with User.id) should not be propagated to upper layer like domain/presentation layer, providing a DataMapper to transform the entity model to a domain model (i.e. a User contains an Order) for the upper layer may be a better option.

Model an object that can have different fields base on a type property

I have an object which can have different fields based on the type property of the object
class Expense {
String id;
String type; // "MILEAGE" or "PERDIEM"
String commonAttribute1;
// there are too many common attribute
Mileage mileage;
PerDiem perDiem;
}
Mileage and PerDiem have different attributes and based on the type, one of them will be null and the other one will be populated.
What is the best way to model such relationship?
I have thought of two ways:
1- Creating different tables for mileage and per diems and link them to the expenses table through a foreign key with one to one relationship.
2- Add both on the same table and based on the type I can fetch from the table any attributes I want, but many columns will be non used.

No "NOT NULL" and "UNIQUE" constraint on Room Persistence Library

While playing with the Room Persistence Library I came to know that there is no methodology to set a data class field with NOT NULL and also UNIQUE constraints. whether SQLite supports those constraints. Isn't it a problem to migrate old database where those constraints are used? Can anyone give a suggestion for this issue?
I came to know that there is no methodology to set a data class field with NOT NULL and also UNIQUE constraints
A #NonNull annotation on an #Entity field will cause that field's column to have NOT NULL applied to it.
unique=true on an #Index will enforce a uniqueness constraint (e.g., #Entity(indices={#Index(value="something", unique=true)}). However, you are correct that a plain UNIQUE constraint on a column, other than via an index, is not supported.
Isn't it a problem to migrate old database where those constraints are used?
Room is not designed to support existing database structures, particularly in the now-current alpha state. Over time, I would expect Room to support a higher percentage of SQLite features, though I will be stunned if it ever reaches 100%.
Complementary answer about NOT NULL for those using Kotlin:
please note that marking a type as non optional will automatically make it not null (and an optional type will not do that).
You can check it in the schema generated by room with #Database(exportSchema = true) on your database.
For example I have something like that:
#Entity(tableName = "messages")
data class Message (
#PrimaryKey
val messageId: UUID = UUID.randomUUID(),
val date: Date = Date(),
val receivedDate: Date? = null
)
And in the generated schema I can read:
"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `date` INTEGER NOT NULL, `receivedDate` INTEGER, PRIMARY KEY(`messageId`))"
(Note: the Date type is here an Int and the UUID a string due to converters I use elsewhere)
If you have multiple item that is to be marked unique & based on that you want to insert in db then you can use composite primary key.
For Not null, Room has provided "#NonNull" annotation that is added over the field that cannot be null.
In the below mentioned eg. roll number is unique in each class but 2 different class can have same roll number. So we can use class & rollNumber as composite primary key & insert in db uniquely.
Example:
#Entity(primaryKeys = {"rollNumber", "class"})
class Student {
#NonNull
private int rollNumber;
private String firstName;
private String lastName;
private int class;
}
for a null able field you can use wrapper primitive type java. for example use Integer instance int in your Room Table.
as in wrapper primitive type java this can bee null but primitive type class cant bee null. and in generation of this SQL code for primitive field that use notNull=true but when use Integer in generayion SQL code use notNull=false

ORMLite not loading child foreign fields

I'm using ORMLite 4.42 for an Android app. I have an entity which has foreign fields. These fields have foreign fields too. The problem is that when I get an element of the root entity, only the first level of foreign fields are loaded. The others levels are null.
On the database every seems ok. The id is correct. Any help?
Edit with models.
The Equipment model is always null when I query by ID. But if I query the whole table, then it gives me access to everything.
TABLE INCIDENT
#DatabaseField(generatedId=true)
private UUID id;
#DatabaseField(foreign=true, foreignAutoRefresh=true, canBeNull=false)
private UserEntity user;
#DatabaseField(dataType = DataType.DATE, canBeNull=true)
private Date date;
#DatabaseField(foreign=true, foreignAutoRefresh=true, canBeNull=true)
private EquipmentEntity equipment;
TABLE EQUIPMENT
#DatabaseField(generatedId=true)
private UUID id;
#DatabaseField(canBeNull=false, unique=true)
private String serial;
#DatabaseField(foreign=true, foreignAutoRefresh=true, canBeNull=false)
private EquipmentTypeEntity type;
TABLE EQUIPMENT TYPE
#DatabaseField(generatedId=true)
private UUID id;
#DatabaseField(canBeNull=true)
private String type;
#DatabaseField(foreign=true, foreignAutoRefresh=true, canBeNull=false)
private EquipmentModelEntity model;
TABLE EQUIPMENT MODEL
#DatabaseField(generatedId=true)
private UUID id;
#DatabaseField(canBeNull=false)
private String model;
I'm using ORMLite 4.42 for an Android app. I have an entity which has foreign fields. These fields have foreign fields too. The problem is that when i get an element of the root entity, only the first level of foreign fields are loaded. The others levels are null.
Right, this is by design. ORMLite specifically limits the number of times it auto-refreshes a sub-element. This was done to protect against huge object trees swallowing memory and against self referential objects.
To quote the docs for foreignAutoRefresh:
NOTE: To protect against recursion, there are a couple of places were auto-refreshing has been limited. If you are auto-refreshing a class that itself has field with foreignAutoRefresh set to true or if you are auto-refreshing a class with a foreign collection, in both cases the resulting field will be set to null and not auto-refreshed. You can always call refresh on the field directly if you need it.
NOTE: If you have an auto-refreshed field that is an object that also has an auto-refreshed field, you may want to tune the maxForeignAutoRefreshLevel value. See below.
To quote from the docs for maxForeignAutoRefreshLevel:
This can be used to set the maximum number of levels to configure foreign objects. For example, if you have a Question which has an foreign field of the best Answer, and the Answer has an foreign field to the corresponding question, then the configuration back and forth can get large. This is especially a problem with auto-refreshed fields when you lookup the Question it could cause an infinite loop. By default, ORMLite only goes through 2 levels but you can decrease it to 1 (0 is not valid) or increase it. The higher the number the more database transactions happen when you load in your Question.
If you increase the maxForeignAutoRefreshLevel to be more then it will issue the extra queries to refresh the elements.
#DatabaseField(foreign=true, foreignAutoRefresh=true, canBeNull=true,
maxForeignAutoRefreshLevel=3)
private EquipmentEntity equipment;

Categories

Resources