Handling Entities and Pojos - android

Still new to Room and while most of the tutorials I've found are related to simple table and CRUD operations I am stuck on evolving this.
Let's take this sample structures.
Users entity
#Entity(tableName = "users")
public class UsersEntity{
#PrimaryKey(autoGenerate = true)
private long id;
#NonNull
private String name;
#NonNull
private long roleId;
}
Roles entity
#Entity(tableName = "roles")
public class RolesEntity{
#PrimaryKey(autoGenerate = true)
private long id;
#NonNull
private String name;
}
First question: Should Entity objects be extended to also replace POJO? Or have Entities and POJO as separate classes?
Extending from the Room setup, the way I would see User POJO is:
public class User{
private long id;
private Role role;
}
Basically this setup should work both if the User would come as a json response from a web service or entered by the user in the app's input fields.
However, this raises the second question: how to insert and retrieve user info?.
Inserting seems possible as there could be something like
userDAO.insertRole(userId)
But how can I get the Role object of User by using Room and the userDAO?
I find inappropriate to do something like:
user = userDao.getUser(userId)
user.setRole(roleDao.getRole(user.getRoleId)
Third question: it seems to be a good practice to have the table columns with _ (eg. role_id) but in java roleId is recommended as class property. If the result of a #Query for instance select role_id from... and the the POJO with roleId field, will fail so the query needs to be select role_id as roleId... to get it work. Is it a good practice to use camel case in table/column names in sqlite?

What you intend as POJO, probably can be seen as a kind of a view model. In general it is a bad idea to unify/link entities and pojos because you are just making a long wider visibilty/scope for the entity, where it is not necessary and can lead to potential problems.
Say you have some client which requires some different visualization of the data, for instance imagine you have a website which exposes a vehicle data and you have implemented everything using metric system, so for distance you have km, for speed km/h and so on. Now your company gains a huge client from UK, and they want you to provide them the data in imperial format. What to do now? Probably implement a deserilization/conversion process which takes the values and converts them according to the context of the user (whether they are using metric or imperial system). What could possibly go wrong if your entity and view model objects are basically the same? Really bad stuff. You have really tight coupling of things, you should implement different getters for serialization for client, for db..it can become a mess.
Instead if you separate the two, you will have your entity which takes care of working with the database, which is standard procedure with small coefficient of variability, and on the other side you will have the view model which is very likely to require frequent modification, after all it is expected, since it is the interface to the final user.

Related

What is the ORM for Android with support #Inheritance(strategy = InheritanceType.SINGLE_TABLE)?

I am developing an android chat application, I have several types of messages inherited from a single abstract class. I want to get a list of different types of chat messages. I think I need an ORM with inheritance support with a SINGLE_TABLE strategy. Is there an ORM for Android with support for this functionality? Or, perhaps, you will advise how to solve this problem using the ORM without SINGLE_TABLE support?
Examples:
public abstract class AbstractMessage implements MessageListContent, Serializable, Comparable<AbstractMessage> {
public enum Status {
DELIVERED,
SENDING_AND_VALIDATION,
NOT_SENDED,
INVALIDATED
}
private SupportedMessageListContentType supportedType = SupportedMessageListContentType.UNDEFINED;
private boolean iSay;
private long timestamp;
private Status status = Status.SENDING_AND_VALIDATION;
private String transactionId;
private String companionId;
// getters and setters
//...
}
public class BasicMessage extends AbstractMessage {
private String text;
private transient Spanned htmlText;
// getters and setters
//...
}
public class TransferMessage extends AbstractMessage {
private BigDecimal amount;
// getters and setters
//...
}
I don't know if you know a lot about ORM's in android, but, two of the most famous ORM's for Android are Room and Realm. And these two could achieve what you want. But, don't take my word on realm, as I am only going to state what my friend told me about realm.
For starters, Room runs in SQLite and Realm in NoSQL. Now, I assume that you know greatly about inheritance and polymorphism, this concept could also be applied to SQL. This is, taking in account that you choose SQLite. Now for realm, it is a different story tho. My friend told me that the polymorphism of your models answers to the polymorphism of the database. Though, I highly doubt that, but I don't like realm, so don't take my word for it.
For choosing your database, I will be frank to tell you to choose SQLite and to help you decide, here is a simple site that currated reasons on which is better, SQL or NoSQL: http://www.nosql-vs-sql.com/

Android Room partly update if exit

I ran across a problem where I am not really sure how to solve it. The project I am working on currently has a model which partly consists of backend stored data and data from the local database.
So what I am trying to Archive is something like that:
Article : [Bunch of Information] & [boolean Subscribed]
The subscribed field is device bound and should not reflect any data on the backend. My question is if it is possible to implement in Room some kind of createIfNotExit() Method that handles the following cases:
Article not present locally: store a copy and set Subscribed to
false
Article present: update all the Information and Keep the
Subscribe-Flag untouched
My idea is to split the model into a separate Subscription-Model holding a reference to the Article. This way I could implement it simply via #Update(OnConfict=Update) etc...
Is there a way to implement a simple #Query method in the DAO that performs what I want?
Sorry if this is a really basic question but I couldn't find any material about best practices handling this case.
Thank you in advance!
For example, your entity is:
#Entity(tableName = "articles")
public final class Article {
#PrimaryKey
public long serverId;
public String title;
public String url;
public boolean isSubscribed;
}
You may write this method in DAO:
#Query("INSERT OR REPLACE INTO articles (serverId, title, url, isSubscribed) VALUES (:id, :title, :url,
COALESCE((SELECT isSubscribed FROM articles WHERE id = :id), 0));")
void insertOrUpdateArticle(long id, String title, String url);
Another option - write this logic in your repository and use two simple operations: select and update

Too many objects to separate UI, domain, and data layers

I am designing my Android app to create model/entity classes separately for web service, database, domain, and UI.
I would be transforming my web service objects into domain objects. Then where I have recycler view, I create UI model objects for each row from my domain which would be a subset.
https://developer.android.com/training/articles/perf-tips.html#ObjectCreation
I have also come across https://github.com/PaNaVTEC/Clean-Contacts which is one sample codebase that strictly separates each layer.
I know it's a trade-off between performance and design, but what is recommended? I really like the design, but my concern is the number of objects instantiated.
My take on this is that it is fine to share entities between different layers of your application as long as doing so does not leak implementation details between the layers.
I would happily share a class such as:
public class Product {
private String name;
private BigDecimal price;
private boolean isInStock;
//..
}
But would not share a class such as:
public class MyNetworkLibraryResponse<T> {
private int status;
private Throwable error;
private T data;
//...
}
If you ever decided to swap MyNetworkLibrary for ShineyNewNetworkLibrary you'd soon come unstuck.
Product however would be an integral part of your Domain. Unless you have a need to re-use View code across business domains you'll likely be better off sharing it than causing increased complexity creating a ProductViewModel

Couchbase lite on Android - General architecture?

We are building a project using couchbase. On Android, I use couchbase lite. Usually, I've been working with relational databases and because I am new to couchbase I am having trouble finding the "correct" architecture. I do understand the core concepts I think, but all the samples and guides seem to stick to some kind of easy setup where they access the database right in the Activities.
I am more used to having some database abstraction where the business logic only get's to see POJO DTO's that are delivered through a database interface or some DAO or something. So I've now annotated my model classes and started writing a simple OR mapper, but with different types of data, foreign keys etc. this is getting quite time consuming quite fast.
Am I completely missing the point here somehow? I can't imagine everyone doing it this way? I everyone writing methods that convert Documents to POJO model classes for each class seperately? Or using a json parser to do that (But that won't work for foreign keys if I wan't to load them too, does it)?
Sorry for the load of questions, but I feel I am missing something obvious here. Thanks!
Will try answering your questions:
Am I completely missing the point here somehow?
No. You can treat noSQL CB as a persistent distributed object cache. So its not RDBMS. However, DAO pattern perfectly fits into this model...since you are dealing with DTOs/ValueObjects/POJOs on DAO level and on noSQL level.
I can't imagine everyone doing it this way?
I suggest write one universal Couchbase manager class that can persist/retrieve a POJO. Then you can re-use it in your DAOs.
Everyone writing methods that convert Documents to POJO model classes
for each class separately? Or using a json parser to do that (But that
won't work for foreign keys if I wan't to load them too, does it)?
You can have one common code in your Couchbase manager class that does conversion from/to json to POJO. So you work with only POJOs and don't see any json in your application code (outside of Couchbase manager class)
Here is an example of such class:
public class CouchbaseManager<K, V>
{
private final Class<V> valueTypeParameterClass;
#Inject
private CouchbaseClient cbClient;
#Inject
private Gson gson;
public CouchbaseManager(final Class<V> valueClass)
{
this.valueTypeParameterClass = valueClass;
}
public V get(K key)
{
V res = null;
String jsonValue = null;
if (key != null)
{
jsonValue = (String) cbClient.get(key);
if (jsonValue != null)
{
res = gson.fromJson(jsonValue, valueTypeParameterClass);
}
}
return res;
}
public void put(K key, V value)
{
int ttl = 0;
cbClient.set(key, ttl, gson.toJson(value, valueTypeParameterClass));
}
}
Then in your DAO code you create instance of CouchbaseManager for each type:
CouchbaseManager<String,Customer> cbmCustomer = new CouchbaseManager<String,Customer>(Customer.class);
CouchbaseManager<String,Account> cbmAccount = new CouchbaseManager<String,Account>(Account.class);
// and so on for other POJOs you have.
// then get/put operations look simple
Customer cust = cbmCustomer.get("cust-1234");
cust.setName("New Name"); // mutate value
// store changes
cbmCustomer.put(cust.getId(), cust);
Now regarding "foreign keys". Remember its not RDBMS so its up to your code to have notion of a "foreign key". For example a Customer class can have an id of an account:
Customer cust = cbmCustomer.get("cust-1234");
String accId = cust.getAccountId();
//You can load account
Account acc = cbmAccount.get(accId);
So as you can see you are doing it all yourself. I wish it was JPA or JDO implementation/provider for Couchbase (like DataNucleus or Hibernate)
You should really start with your POJO/Document design to try to split your POJO entities into "chunks" of data to get a right balance between coarse vs fine grained POJOs.
Also see this discussion on key/document design considerations.

Persisting entity relationships from REST service for Android

I am trying to maintain a local store of a database, accessible via a REST API. I am attempting to use the fantastic RoboSpice and Spring libraries for the REST client, Jackson to parse/cache the JSON response and ORMLite to persist the resulting objects.
The problem is that I don't know how to store foreign object relationships for the JSON responses I get. Sometimes the JSON objects are nested, other times they are referenced by Id.
A typical systems response
{
id:567,
name:"The only system",
competitions:[{
id:123,
system_id:567
...
}];
}
A competitions response
items: {
123:{
id:123,
system_id:567 // System only referenced by id
...
}}
Another competitions response
items: {
123:{
id:123,
system_id:567, // System referenced by id and nested
system:{
id:567,
name:"The only system",
...
}
}
}
Nested objects work fine, but it's the cases where there is a reference by id that is killing it. I have two classes for my data model as follows.
Systems class
#DatabaseTable("systems")
public class System {
#JsonProperty("id")
#DatabaseField(id=true, columnName="id")
private long id;
#JsonProperty("name")
#DatabaseField(columnName="name")
private String name;
#JsonProperty("competitions")
#ForeignCollectionField
private ForeignCollection<Competition> competitions;
// getters & setters omitted
}
Competition class
#DatabaseTable("competitions")
public class Competition {
#JsonProperty("id")
#DatabaseField(id=true,columnName="id")
private long id;
#JsonProperty("system_id")
#DatabaseField(columnName="id")
private long systemId; // This is definitely at least part of the problem
#JsonProperty("system")
#DatabaseField(foreign=true, columnName="system_id")
private System system;
// getters & setters omitted
}
Having two properties references the system_id seems like a definitively bad idea, but I can't find an alternative for the behaviour I want. Even if the system object is not nested in the Competition object, the Competition should be able to map a relationship to the System object in the local database, because the id of the system is always provided.
The other problem I suspect is that I'm using two object persisters, the JacksonObjectPersister and the InDatabaseObjectPersisterFactory (provided by RoboSpice for use with ORMLite). The reason for this is because I don't want to persist the lists that the objects are nested in to the database. By my understanding, Jackson should cache the JSON response from the server, ORMLite should cache the data model.
This is the error I'm getting
02-03 15:15:57.640: D//DefaultRequestRunner.java:166(20944): 15:15:57.636 Thread-28
An exception occurred during service execution :org.codehaus.jackson.map.JsonMappingException:(was java.lang.NullPointerException)
(through reference chain: com.company.app.api.objects.List["items"]->
java.util.HashMap["51"]->
com.company.app.api.objects.Competition["system_id"])
Apologies for what seems like a number of questions in one, I am bashing my head against a wall. I will attempt to wrap this essay up with a summary...
Is there any way to piece together object relationships using Jackson and ORMLite for the JSON responses I have provided?

Categories

Resources