需求場景:sqlite數(shù)據(jù)庫只能直接存儲數(shù)字渗钉、字符串晌姚、日期等簡單類型,如果要存儲一個(gè)復(fù)雜對象的話需要把對象拆解為一個(gè)個(gè)簡單數(shù)據(jù)類型挥唠,畢竟再復(fù)雜的數(shù)據(jù)類型也是由簡單數(shù)據(jù)類型組合而來宝磨。本以為大名鼎鼎的GreenDao可以幫我們智能拆解、組裝對象世囊,結(jié)果搜了一圈竟然找不到?jīng)]找到存儲自定義類型的辦法窿祥。
好在在官方文檔上找到解決方案:
@Entity
public class User {
@Id
private Long id;
@Convert(converter = RoleConverter.class, dbType = Integer.class)
private Role role;
public enum Role {
DEFAULT(0), AUTHOR(1), ADMIN(2);
final int id;
Role(int id) {
this.id = id;
}
}
public static class RoleConverter implements PropertyConverter<Role, Integer> {
@Override
public Role convertToEntityProperty(Integer databaseValue) {
if (databaseValue == null) {
return null;
}
for (Role role : Role.values()) {
if (role.id == databaseValue) {
return role;
}
}
return Role.DEFAULT;
}
@Override
public Integer convertToDatabaseValue(Role entityProperty) {
return entityProperty == null ? null : entityProperty.id;
}
}
}
可以看到這個(gè)實(shí)體類里包含了一個(gè)自定義的枚舉類型Role晒衩,在該類型上加了一個(gè)@Convert注解听系,括號里面指定了用于轉(zhuǎn)換對象類型和數(shù)據(jù)庫類型的converter類,以及該對象存儲在數(shù)據(jù)庫中的類型靠胜。
再來看看這個(gè)converter類做了什么事情浪漠。很簡單,它實(shí)現(xiàn)了PropertyConverter接口该镣,里面有兩個(gè)方法必盖,convertToEntityProperty是將數(shù)據(jù)庫中的類型轉(zhuǎn)換為java實(shí)體類俱饿;convertToDatabaseValue方法相反,將java實(shí)體類轉(zhuǎn)換為數(shù)據(jù)庫中的類型失驶。我們只要在這兩個(gè)方法里定義相應(yīng)的轉(zhuǎn)換規(guī)則即可枣购。
看上去也不難擦耀,思路也很清晰涩堤。但是這個(gè)例子里的Enum類型要轉(zhuǎn)換為int類型還是比較簡單的,而筆者要存儲的對象要復(fù)雜的多吁系。這還是解決不了我的需求鞍谆辍(欲哭無淚)。
如何快速簡單的把一個(gè)復(fù)雜的數(shù)據(jù)類型轉(zhuǎn)換為簡單數(shù)據(jù)類型蕴坪,而且還要能精準(zhǔn)地轉(zhuǎn)換回來敬锐?好像是有這么一個(gè)東西滞造,json!Mφ买窟!json作為客戶端和服務(wù)端之間數(shù)據(jù)傳遞的載體,確實(shí)滿足我們現(xiàn)在的業(yè)務(wù)需求瞳购。更棒的是我們有g(shù)son這個(gè)解析框架來幫我們做轉(zhuǎn)換!那么我們要做的事真就是無腦操作了亏推。來看看我的Demo代碼:
@Entity(
)
public class Zoo {
indexes = {
@Index(value = "zooId DESC, zoneId DESC", unique = true)
}
@Id(autoincrement = true)
private Long id;
@Property
private Long zooId;
@Property
private Long zoneId;
@Property
@Convert(converter = CatConverter.class, columnType = String.class)
private Cat cat;
public static class CatConverter implements PropertyConverter<Cat, String> {
@Override
public Cat convertToEntityProperty(String databaseValue) {
if (databaseValue == null) {
return null;
}
return new Gson().fromJson(databaseValue, Cat.class);
}
@Override
public String convertToDatabaseValue(Cat entityProperty) {
if (entityProperty == null) {
return null;
}
return new Gson().toJson(entityProperty);
}
}
}
這里我新建了一個(gè)叫Zoo的實(shí)體学赛,里面包含一個(gè)Cat類型的對象,且不管該對象復(fù)雜與簡單吞杭,我們甚至都不需要關(guān)心它的具體數(shù)據(jù)結(jié)構(gòu)盏浇。加上@Convert注解后新建一個(gè)CatConverter類(注意converter類是內(nèi)部類的話要聲明為static),因?yàn)槲覀円D(zhuǎn)換為json存儲起來所以數(shù)據(jù)庫中的類型肯定是String了芽狗,標(biāo)注好泛型绢掰,做一個(gè)參數(shù)的非空判斷(良好習(xí)慣)。在轉(zhuǎn)換的方法內(nèi)部我們只需要利用gson將數(shù)據(jù)在java bean類型和json之間轉(zhuǎn)換,就可以完成我們的需求了滴劲,是不是很簡單呢攻晒?
Cat miaomiao = new Cat(13, "miaomiao");
Cat jingjing = new Cat(13, "jingjing");
ZooDao zooDao = daoSession.getZooDao();
zooDao.insertOrReplace(new Zoo(null, 222L, 333L, miaomiao));
zooDao.insertOrReplace(new Zoo(null, 222L, 331L, jingjing));
List<Zoo> zoos = zooDao.queryBuilder().list();
for (Zoo zoo : zoos) {
Log.d("xxx", zoo.getZooId()+":"+zoo.getZoneId()+":"+zoo.getCat().toString());
}
寫完代碼后make project自動生成新的ZooDao類(有興趣的可以看看這個(gè)類班挖,其實(shí)也挺簡單的)鲁捏,不放心趕緊實(shí)驗(yàn)一下能不能直接存取自定義對象了。