Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using UUID for Primary Key using Room with Android

I need to sync my Android mobile app with a multi-tenant database in the cloud. I thought the best way to do this was using a UUID for the Primary Key of my tables. I just started using Room and was wondering where/how I might do this and was looking for 1) opinions on using UUID as a PK with Room and 2) where I would implement this (in the model initializing the id column as this is the only way to use @NonNull)?

UPDATE

I used INTs but am not convinced it was the right approach. I saw an example from the android developer site which showed a uuid being used. Certainly would help my cloud syncing routine, but at the expense of speed and space. I was thinking of a hybrid approach where INTs were used for PKs but UUIDs as an additional field. This way I would not have to replicate each UUID for FKs. I did some modeling and it looks like the hybrid approach would be 50% of the size of the full UUID approach (the INT only would be 25% as big).

Has anybody struggled with this same issue? Did you choose a direction (UUID, INT, or hybrid) and did you regret it or did it work well?

like image 865
lcj Avatar asked Jan 03 '20 03:01

lcj


1 Answers

  1. There was several reasons you have to use UUID instead of int as primary key.For example your application is a distributed application like many people use many devices edit one documente and you will log everyones' edit log for the version control feature. If your application is centralized(most cases), it is better to use int, or request the primary key(can be int, long or whatever) from the server. If you have to use UUID, then use it. Otherwise the int or long is a better choice.

  2. At the end I will attach an example of using UUID as the primary key with android Room.

  3. UUID storage space and computing speed should not be the primary consideration, unless you have encountered these problems (no need to over-optimize). For example: the storage space of a picture may be about 1MB, the UUID is saved in the database in the form of String, in utf-8 format, up to 144 Byte (int is 4 Byte), which is about 1/7000 of a picture . On the server side, UUID is not recommended as the primary key, because the server serves tens of thousands of users at the same time, and there are many queries at the same time. Although the mobile phone CPU is far weaker than the server CPU, it only serves one user at a time. Again, in scenarios where UUID has to be used, there is no need to consider optimization issues in advance.

Book.class

@Entity(tableName = "books")
public class Book{
@PrimaryKey
@NonNull
private UUID id;
private String title;
private Date date;

public Book() {
    this.id = UUID.randomUUID();
    date = new Date();
}

public UUID getId() {
    return id;
}

public void setId(UUID id) {
    this.id = id;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public Date getDate() {
    return date;
}

public void setDate(Date date) {
    this.date = date;
}

}

AppDatabase.class

@Database(entities = {Book.class}, version = 1, exportSchema = false)
@TypeConverters({UUIDConverter.class, DateConverter.class})
public abstract class AppDatabase extends RoomDatabase {
    private static AppDatabase INSTANCE;
    private static final String DATABASE_NAME = "BookDatabase";

    public abstract BookDao bookDao();

    public static void init(Context context) {
        if (INSTANCE == null) {
            INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME).build();
        }
    }

    public static AppDatabase getINSTANCE() {
        if (INSTANCE == null) throw new IllegalStateException("init in MyApplication.class");
        return INSTANCE;
    }
}

Converters: converters convert uuid or other format that sqlite do not support to a support type. Edit: From Version 2.4.0-alpha05 default converter for UUID exists which is using byte array instead of String. Linking change which can be handy for migration.

public class UUIDConverter {

    @TypeConverter
    public static String fromUUID(UUID uuid) {
        return uuid.toString();
    }

    @TypeConverter
    public static UUID uuidFromString(String string) {
        return UUID.fromString(string);
    }
}

public class DateConverter {

    @TypeConverter
    public static long timestampFromDate(Date date) {
        return date.getTime();
    }

    @TypeConverter
    public static Date dateFromTimestamp(long timestamp) {
        return new Date(timestamp);
    }
}
like image 118
zz-m Avatar answered Nov 03 '22 19:11

zz-m