How do I set a unique primary key in Realm? - android

How do I set a unique primary key in Realm in Android? The Realm documentation says I cannot use anything but String or int/long, so is UUID type is out of the question too? What if I have items with the same name?
e.g.
public class GroceryItem extends RealmObject {
#PrimaryKey
private long id; <--- how can I make this unique without UUID?
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} }

Realm doesn't support any autoincrement for primary keys. Visit docs for more information about this. So, you are to handle it by yourself.
1) Use should use UUID. You can also get long, int or String value from it:
long: UUID.randomUUID().getMostSignificantBits();
int: (int) UUID.randomUUID().getMostSignificantBits();
String: UUID.randomUUID().toString();
2) Or you can query some data from your database and apply some rules to generate a new key. For example, query for the last element and increment it's primarykey. But that's not ideal way.

Related

Android Firebase, Unable to fetch the data

I created a family tree application on java and mysql database. Now I am testing an android app for the same. So I converted my mysql database file to JSON format and uploaded it to firebase. When I am inserting records on it, it is working perfectly fine but when I try to fetch the data it is showing the error:
com.google.firebase.database.DatabaseException: Failed to convert a value of type java.lang.String to int
at com.google.android.gms.internal.firebase_database.zzkt.zzb(Unknown Source:180)
What should be the problem? I tried deleting the data from the database which I uploaded through JSON file and then inserted records directly from app into database and fetch them, it worked fine but when I am adding record from JSON file only then It is creating problem.
here is the code from the app for fetching data:
public void clicked(){
mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Family> FamilyList = new ArrayList<>();
for (DataSnapshot adSnapshot: dataSnapshot.getChildren()) {
Family f = adSnapshot.getValue(Family.class);
FamilyList.add(f);
// adsList.add(adSnapshot.getValue(Family.class));
}
Toast.makeText(MainActivity.this, "Total Records: "+FamilyList.size(), Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Family Model Class:
public class Family {
int id;
String name;
String fatherName;
int fid;
String city;
String state;
public Family(int id, String name, String fatherName, int fid, String city, String state) {
this.id = id;
this.name = name;
this.fatherName = fatherName;
this.fid = fid;
this.city = city;
this.state = state;
}
public Family()
{
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFatherName() {
return fatherName;
}
public void setFatherName(String fatherName) {
this.fatherName = fatherName;
}
public int getFid() {
return fid;
}
public void setFid(int fid) {
this.fid = fid;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
Here is the JSON Record Sample
It is the records which I entered through App
I think the converted JSON treated id and fid as String, while in mySQL they are int. (am I correct?)
Tell me if any other code is needed.
The problem relies on here
Family f = adSnapshot.getValue(Family.class);
you are trying to get data in an inappropriate type.
You should correct this by checking Family.class and check if the values there are the same as they are in your database structure in firebase, it will be helpful if you put your database structure here, or some images.
Check if for example in Family.class you have in your variable types the same as they are in firebase, with the same name also.
So for example if in firebase there is an string called name you should have in your constructor inside Family.class the same type and name.
String name;
and in Firebase your json key should be name too.
For instance, check this
your Family class for example should have the variables with the same name and type as your database.
Also check, if the value in firebase has "" is an String type and in your POJO you should have a variable with the type String for what you are trying to access, but if the value dosnt have "" it should be a long , int, double or any type of number.
EDIT: check this structure
It has all the values types as String, but in your Family.class you have the values right for this type of structure.
you should change your database at firebase so all your types matches with the ones in your Family.class, either way it won't fetch your values
Note: if you want to fetch all your values like they are at the first image, just change in Family.class from this:
int id;
String name;
String fatherName;
int fid;
String city;
String state;
to this:
String id;
String name;
String fatherName;
String fid;
String city;
String state;
Also change your constructor types and everything to match all Strings
The thing is that firebase creates unique IDs for each element in your database structure, and the types imported from your MySQL database are not the same as the firebase ones, I suggest you to either change your Family.class variable types as I mentioned above, or replicate your MySQL database with firebase and the same variable types.
This is happening because you have a variable of integer datatype in your model but you are returning String from Firebase... either convert your variable to string or return integer from firebase....
Both model and Firebase variable should be of a same data type.
As per your below error:-
com.google.firebase.database.DatabaseException: Failed to convert a value of type java.lang.String to int at com.google.android.gms.internal.firebase_database.zzkt.zzb(Unknown Source:180)
I think, you need to check somewhere you tried to store value in int which is store in firebase in string.
So first check it and if necessary to cast then casting your value using Integer.parseInt or Integer.valueof
for example,
Integer.valueOf(dataSnapShot.getValue());
or
Integer.parseInt(dataSnapShot.getValue());
For more understanding this you can also refer stack overflow's below links:
Firebase DatabaseException: Failed to convert value of type java.lang.Long to String
com.google.firebase.database.DatabaseException: Failed to convert a value of type java.lang.String to double
Firebase android error "Failed to convert value of type "

How to store a object array by using Room in Android?

I want to cache a song-list in my app, the Song-list structure is like below:
#Entity
public class Songlist {
String _id;
String desc;
List<SongDesc> songWithComment;
.....
public static class SongDesc {
String comment;
Song song;
}
}
#Entity
pulbic class Song {
String name;
String type;
......
}
The lib of operating sqlite3 is android.arch.persistence.room, but it dosen't allow object references in a table.Is there any way to cache a song-list by using Room in Android?
Also if you want to store some custom objects, you can use #Embedded annotation like in example bellow :
class Address {
public String street;
public String state;
public String city;
#ColumnInfo(name = "post_code")
public int postCode;
}
#Entity
class User {
#PrimaryKey
public int id;
public String firstName;
#Embedded
public Address address;
}
If you want to save an ArrayList of some type into the database, you shuld use TypeConverter to convert the ArrayList from and into a simpler recognizable type to the database engine, like a String.
See this:
Android Room Database: How to handle Arraylist in an Entity?
and https://commonsware.com/AndroidArch/previews/room-and-custom-types

Auto increment primary key in sugar orm

How can define an auto increment primary key in Sugar model?
Do Sugar automatically creates unique ID for each record
import com.orm.SugarRecord;
public class Customers extends SugarRecord {
int id; // this field must be auto increment primary key
String name;
String tel;
String mobile;
String address;
String create_date;
public Customers(){}
public Customers(int id, String name, String tel, String mobile, String address, String create_date){
this.id = id;
this.name = name;
this.tel = tel;
this.mobile = mobile;
this.address = address;
this.create_date = create_date;
}
}
You may create a custom table my annotating your class with "#Table", but you should create a long type of "id" for the ORM to work with. The best way would be to let sugar do all the work.
Sugar will create an id field (you do not need to include in your class) and you may access it using "getId()" something like:
Customers customer = Customers.findById(Customers.class, 1)
long customer_id = customer.getId();

How to get timestamp(rowversion) from sql azure to android with mobileservice

i have a problem getting timestamp(rowversion) from my SQL Azure database.
In my tables there is a column with datatype timestamp. This timestamp isn't similar to datetime, it's more like a rowversion.
I can get all other data in this table with the query from MobileServiceTable, there is no problem.
But this special datatype is a problem.
My class for this table looks like:
public class ArbeitsgangBezeichnung {
#com.google.gson.annotations.SerializedName("id")
private int ID;
#com.google.gson.annotations.SerializedName("ABZ_ArbeitsgangBezeichnungID")
private int ABZ_ArbeitsgangBezeichnungID;
#com.google.gson.annotations.SerializedName("ABZ_Bezeichnung")
private String ABZ_Bezeichnung;
#com.google.gson.annotations.SerializedName("ABZ_RowVersion")
private StringMap<Number> ABZ_RowVersion;
//constructor, getter, setter, etc....
}
If i login in Azure and look at the table, there are my example values and the automatic generated timestamp. The timestamp value looks like "AAAAAAAAB/M=". If i login in sql database and let me show the data, then for timestamp there is only "binarydata" (in pointed brackets) and not that value as it is shown in Azure.
The variable "ABZ_RowVersion" should include this timestamp, but the data in the StringMap doesn't look like the one in Azure. I tried String and Byte as datatype for the StringMap, but it doesn't helped.
I tried byte[] for ABZ_RowVersion, but then i got an exception in the callback method.
Then i tried Object for ABZ_RowVersion, that time i found out, that it is a StringMap, but nothing more.
Does anybody know, how to get the data from timestamp, i need it for comparison.
Thanks already
When you create a timestamp column in a table, it's essentially a varbinary(8) column. In the node SQL driver, it's mapped to a Buffer type (the usual node.js type used for binary data). The object which you see ({"0":0, "1":0, ..., "length":8}) is the way that a buffer is stringified into JSON. That representation doesn't map to the default byte array representation from the Gson serializer in Android (or to the byte[] in the managed code).
To be able to use timestamp columns, the first thing you need to do is to "teach" the serializer how to understand the format of the column returned by the server. You can do that with a JsonDeserializer<byte[]> class:
public class ByteArrayFromNodeBufferGsonSerializer
implements JsonDeserializer<byte[]> {
#Override
public byte[] deserialize(JsonElement element, Type type,
JsonDeserializationContext context) throws JsonParseException {
if (element == null || element.isJsonNull()) {
return null;
} else {
JsonObject jo = element.getAsJsonObject();
int len = jo.get("length").getAsInt();
byte[] result = new byte[len];
for (int i = 0; i < len; i++) {
String key = Integer.toString(i);
result[i] = jo.get(key).getAsByte();
}
return result;
}
}
}
Now you should be able to read data. There's still another problem, though. On insert and update operations, the value of the column is sent by the client, and SQL doesn't let you set them in them. So let's take this class:
public class Test {
#SerializedName("id")
private int mId;
#SerializedName("name")
private String mName;
#SerializedName("version")
private byte[] mVersion;
public int getId() { return mId; }
public void setId(int id) { this.mId = id; }
public String getName() { return mName; }
public void setName(String name) { this.mName = name; }
public byte[] getVersion() { return mVersion; }
public void setVersion(byte[] version) { this.mVersion = version; }
}
On the insert and update operations, the first thing we need to do in the server-side script is to remove that property from the object. And there's another issue: after the insert is done, the runtime doesn't return the rowversion property (i.e., it doesn't update the item variable. So we need to perform a lookup against the DB to retrieve that column as well:
function insert(item, user, request) {
delete item.version;
request.execute({
success: function() {
tables.current.lookup(item.id, {
success: function(inserted) {
request.respond(201, inserted);
}
});
}
});
}
And the same on update:
function update(item, user, request) {
delete item.version;
request.execute({
success: function() {
tables.current.lookup(item.id, {
success: function(updated) {
request.respond(200, updated);
}
});
}
});
}
Now, this definitely is a lot of work - the support for this type of column should be better. I've created a feature request in the UserVoice page at http://mobileservices.uservoice.com/forums/182281-feature-requests/suggestions/4670504-better-support-for-timestamp-columns, so feel free to vote it up to help the team prioritize it.

GSON does not cast Json string to class

I am trying to convert JSonObject string to some specific classes.
MyClass mc= new Gson().fromJson(jo.toString(),MyClass.class);
After this step all values of mc is null.
Value of the jo.toString() :
{
"__type":"MyClass:#MyProject.Model",
"ID":1,
"Comment":"First Record",
"SubClassID":534,
"Active":true,
"Date":"\/Date(1323087840000+0200)\/"
}
MyClass.java has attributes ID, Comment...
Thanks Regards...
MyClass.Java:
public class MyClass extends ABase
{
private String _Comment;
public String getComment(){
return _Comment;
}
public void setComment(String value){
_Comment = value;
}
private Integer _ID;
public Integer getID(){
return _ID;
}
public void setID(Integer value){
_ID = value;
}
private java.util.Date _Date;
public java.util.Date getDate(){
return _Date;
}
public void setDate(java.util.Date value){
_Date = value;
}
}
The problem is that the JSON element names do not match the Java field names, and no explicit alternative name-mapping configuration was provided to Gson.
Possible Solutions:
Change the Java field names to exactly match the JSON element names. This of course isn't always possible, e.g., when the JSON element names include characters or formats not valid for Java field names.
Change the JSON element names to exactly match the Java field names. This of course isn't always possible, e.g., when the JSON is from a third party.
Provide Gson with name-mappings, using either the #SerializedName annotation, or a FieldNamingPolicy.

Categories

Resources