1.引言
目前做的一款app坠宴,全部都是基于本地?cái)?shù)據(jù)庫(kù)粉私,于是采用第三方數(shù)據(jù)庫(kù)greendao。因?yàn)橹皩?duì)greendao沒(méi)有深層次的研究壁顶,都是照著博客上學(xué)的珠洗,沒(méi)想到被博客坑了。網(wǎng)上搜索的千篇一律若专,都是照著官網(wǎng)上翻譯的许蓖,有很多需要著重注意的地方都被忽略了,導(dǎo)致我在使用的時(shí)候遇到大量的坑调衰。因此我單獨(dú)的寫(xiě)了一個(gè)簡(jiǎn)單的項(xiàng)目來(lái)驗(yàn)證我踩過(guò)的坑膊爪。但是有些情況卻沒(méi)有出現(xiàn),不得其解嚎莉。
官網(wǎng)的地址
2.正文
2.1 @ToOne
一節(jié)課一個(gè)學(xué)生對(duì)應(yīng)一個(gè)老師米酬,所以學(xué)生:老師=1:1
@Entity
public class Student {
@Id
private Long id;//主鍵
private Long tid;//外鍵
@ToOne(joinProperty = "tid")
private Teacher teacher;
}
teacher:
@Entity
public class Teacher {
@Id
private Long id;//主鍵
private Long idCard;//身份證號(hào)碼
}
插入student和techaer:
DaoSession daoSession = daoMaster.newSession();
StudentDao studentDao = daoSession.getStudentDao();
TeacherDao teacherDao = daoSession.getTeacherDao();
Student student=new Student();
Teacher teacher=new Teacher();
teacher.setIdCard(333L);
Long key=teacherDao.insert(teacher);
student.setTid(key);
studentDao.insert(student);
當(dāng)然通過(guò)student.setTeacher();來(lái)進(jìn)行級(jí)聯(lián)插入也是可以的。親測(cè)趋箩。
注意:load()和loadDeep()
load()查詢(xún)赃额。不會(huì)把外鍵的信息查詢(xún)出來(lái)。但是假如人為的調(diào)用setTeacher,之后再load()查詢(xún)叫确,就會(huì)把Teacher的信息也查找出來(lái)
loadDeep:會(huì)將所有的信息都查詢(xún)出來(lái)跳芳,包括外鍵。
2.2 外鍵必須是關(guān)聯(lián)表的主鍵竹勉。
我想把身份證id作為student表中的外鍵飞盆。但是實(shí)際make project的時(shí)候報(bào)錯(cuò)。
student表:
@Entity
public class Student {
@Id
private Long id;//主鍵
private String teacherIdCard;//外鍵
@ToOne(joinProperty = "teacherIdCard")
private Teacher teacher;
}
teacher表:
@Entity
public class Teacher {
@Id
private Long id;//主鍵
private String idCard;//身份證號(hào)碼
public String getIdCard() {
return this.idCard;
}
}
2.3 @Unite的使用饶米。
項(xiàng)目中桨啃,我本地表都是已經(jīng)存在的不是自己建立的∶适洌或許就是因?yàn)樽约航⒌亩皇巧傻膶?dǎo)致照瘾。@Unique沒(méi)得反應(yīng),md丧慈。
@Entity(createInDb = false)
public class Teacher implements Serializable{
@Id
@Property(nameInDb = "tid")
private Long tid;//主鍵
@Unique
private String idCard;//身份證號(hào)碼
這樣做就行了析命。
2.4 將生成的db文件放到指定的文件路徑下主卫。網(wǎng)上有現(xiàn)成的代碼。在此把項(xiàng)目中的粘貼下鹃愤。
public class GreenDaoContext extends ContextWrapper {
private String currentUserId;
private Context mContext;
public GreenDaoContext() {
super(XinYiApplication.instance);
this.mContext = XinYiApplication.instance;
}
/**
* 獲得數(shù)據(jù)庫(kù)路徑芒涡,如果不存在浅缸,則創(chuàng)建對(duì)象
* @param dbName
*/
@Override
public File getDatabasePath(String dbName) {
// 判斷是否存在sd卡
boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState());
if (!sdExist) {// 如果不存在,
Log.e("SD卡管理:", "SD卡不存在栏渺,請(qǐng)加載SD卡");
return null;
} else {// 如果存在
// 獲取sd卡路徑
String dbDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
dbDir += "/mlapp";// 數(shù)據(jù)庫(kù)所在目錄
String dbPath = dbDir+"/"+dbName;// 數(shù)據(jù)庫(kù)路徑
// 判斷目錄是否存在怔接,不存在則創(chuàng)建該目錄
File dirFile = new File(dbDir);
if (!dirFile.exists())
dirFile.mkdirs();
// 數(shù)據(jù)庫(kù)文件是否創(chuàng)建成功
boolean isFileCreateSuccess = false;
// 判斷文件是否存在,不存在則創(chuàng)建該文件
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
try {
isFileCreateSuccess = dbFile.createNewFile();// 創(chuàng)建文件
} catch (IOException e) {
e.printStackTrace();
}
} else {
isFileCreateSuccess = true;
}
// 返回?cái)?shù)據(jù)庫(kù)文件對(duì)象
if (isFileCreateSuccess) {
return dbFile;
} else {
return super.getDatabasePath(dbName);
}
}
}
/**
* 重載這個(gè)方法凹耙,是用來(lái)打開(kāi)SD卡上的數(shù)據(jù)庫(kù)的姿现,android 2.3及以下會(huì)調(diào)用這個(gè)方法。
*
* @param name
* @param mode
* @param factory
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
SQLiteDatabase.CursorFactory factory) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
return result;
}
/**
* Android 4.0會(huì)調(diào)用此方法獲取數(shù)據(jù)庫(kù)肖抱。
*
* @param name
* @param mode
* @param factory
* @param errorHandler
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int,
* android.database.sqlite.SQLiteDatabase.CursorFactory,
* android.database.DatabaseErrorHandler)
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory,
DatabaseErrorHandler errorHandler) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
return result;
}
}
然后通過(guò)如下的方法得到daoSession
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(new GreenDaoContext(), "POSTerminal.db", null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession();
2.4 將db文件拷貝到指定文件夾下
public class CopyDBUtil {
public static void copyRawDBToApkDb() {
OutputStream outputStream=null;
InputStream inputStream=null;
String apkDbPath = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/POSTerminal";
String dbName = "/POSTerminal.db";
boolean b = false;
File f = new File(apkDbPath);
if (!f.exists()) {
f.mkdirs();
}
File dbFile = new File(apkDbPath + dbName);
if (dbFile.exists()) {
dbFile.delete();
}
try {
dbFile.createNewFile();
outputStream = new FileOutputStream(dbFile);//寫(xiě)入流
inputStream = new FileInputStream(new File(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/mlapp/POSTerminal.db"));
byte[] bytes = new byte[1024];
int length;
while ((length = inputStream.read(bytes)) > 0) {
outputStream.write(bytes, 0, length);
}
//寫(xiě)完后刷新
outputStream.flush();
ToastUtil.showLong(XinYiApplication.instance,"復(fù)制成功");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (inputStream != null) {//關(guān)閉流备典,釋放資源
inputStream.close();
}
if(outputStream!=null){
outputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.5 建立索引(或者設(shè)置唯一屬性)
@Entity( indexes = {
@Index(value = "idCard", unique = true)
})
public class Teacher implements Serializable{
@Id
@Property(nameInDb = "tid")
private Long tid;//主鍵
private String idCard;//身份證號(hào)碼
}
idCard屬性被插入一樣的值 就會(huì)報(bào)錯(cuò)。
2.6 @ToMany
一個(gè)老師對(duì)應(yīng)多個(gè)學(xué)生即1:N意述。
@ToMany 有三種情況提佣,根據(jù)需要選用不同的情況。
2.61 referencedJoinProperty 關(guān)聯(lián)
@Entity
public class Teacher implements Serializable {
@Id
private Long id;//主鍵
private String name;
@Unique
private Long idCard;//身份證號(hào)碼
//與上面的屬性沒(méi)得關(guān)系荤崇。referencedJoinProperty 與Student里面的idCard 相關(guān)拌屏。且是主鍵關(guān)聯(lián)
@ToMany(referencedJoinProperty = "idCard")
private List<Student> students;
}
student表:
@Entity
public class Student {
@Id
public Long id;
private String name;
//Teacher的主鍵(必須是主鍵,)
public Long idCard;
}
總結(jié):A:B=1:N 假如是通過(guò)referencedJoinProperty 關(guān)聯(lián)的話(huà)天试,B里面有A的主鍵,屬性不同沒(méi)得關(guān)系..A里面的referencedJoinProperty 指向B中的A的主鍵表示的屬性槐壳。。例如上面的B_idCard.
2.62 joinProperties 關(guān)聯(lián)
teacher類(lèi)的定義:
@Entity
public class Teacher {
@Id
private Long id;
private String teacherName;
//一下的是一體的
@NotNull
private Long tidCard;
@ToMany(joinProperties = {
@JoinProperty(name = "tidCard", referencedName = "tidCard")
})
private List<Student> students;
student類(lèi)的定義:
@Entity
public class Student {
@Id
private Long id;
@NotNull
private Long tidCard;
joinProperties 屬性將Teacher 里面的獨(dú)一的非主鍵喜每,當(dāng)做Student的外鍵。referencedJoinProperty 關(guān)聯(lián) 必須是主鍵作為Student的外鍵雳攘。
@ToMany注意:
通過(guò)查找teacher带兜,能獲得List<Student>。實(shí)際上當(dāng)你查找得到一個(gè)Teacher 對(duì)象的時(shí)候吨灭,其實(shí)List<Student>這個(gè)時(shí)候?yàn)榭盏母照铡V挥挟?dāng)你調(diào)用getStudents()的時(shí)候才會(huì)進(jìn)行查找。喧兄。這個(gè)與@ToOne的差別无畔。
greendao的總結(jié)就到這里,以后看博客真的要先看英文文檔吠冤。