Android greendao实践教程

1.引言

目前做的一款app,全部都是基于本地数据库,于是采用第三方数据库greendao。因为之前对greendao没有深层次的研究,都是照着博客上学的,没想到被博客坑了。网上搜索的千篇一律,都是照着官网上翻译的,有很多需要着重注意的地方都被忽略了,导致我在使用的时候遇到大量的坑。因此我单独的写了一个简单的项目来验证我踩过的坑。但是有些情况却没有出现,不得其解。
官网的地址

2.正文

2.1 @ToOne

一节课一个学生对应一个老师,所以学生:老师=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;//身份证号码

}

插入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);

当然通过student.setTeacher();来进行级联插入也是可以的。亲测。

注意:load()和loadDeep()

load()查询。不会把外键的信息查询出来。但是假如人为的调用setTeacher,之后再load()查询,就会把Teacher的信息也查找出来

loadDeep:会将所有的信息都查询出来,包括外键。

2.2 外键必须是关联表的主键。

我想把身份证id作为student表中的外键。但是实际make project的时候报错。
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;//身份证号码
    public String getIdCard() {
        return this.idCard;
    }
}
Android greendao实践教程_第1张图片
image.png

2.3 @Unite的使用。

项目中,我本地表都是已经存在的不是自己建立的。或许就是因为自己建立的而不是生成的导致。@Unique没得反应,md。

@Entity(createInDb = false)
public class Teacher implements Serializable{
    @Id
    @Property(nameInDb = "tid")
    private Long tid;//主键

    @Unique
    private String idCard;//身份证号码

这样做就行了。

2.4 将生成的db文件放到指定的文件路径下。网上有现成的代码。在此把项目中的粘贴下。

public class GreenDaoContext extends ContextWrapper {
    private String currentUserId;
    private Context mContext;

    public GreenDaoContext() {
        super(XinYiApplication.instance);
        this.mContext = XinYiApplication.instance;
    }

    /**
     * 获得数据库路径,如果不存在,则创建对象
     * @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卡不存在,请加载SD卡");
            return null;
        } else {// 如果存在
            // 获取sd卡路径
            String dbDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
            dbDir += "/mlapp";// 数据库所在目录
            String dbPath = dbDir+"/"+dbName;// 数据库路径
            // 判断目录是否存在,不存在则创建该目录
            File dirFile = new File(dbDir);
            if (!dirFile.exists())
                dirFile.mkdirs();

            // 数据库文件是否创建成功
            boolean isFileCreateSuccess = false;
            // 判断文件是否存在,不存在则创建该文件
            File dbFile = new File(dbPath);
            if (!dbFile.exists()) {
                try {
                    isFileCreateSuccess = dbFile.createNewFile();// 创建文件
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                isFileCreateSuccess = true;
            }
            // 返回数据库文件对象
            if (isFileCreateSuccess) {
                return dbFile;
            } else {
                return super.getDatabasePath(dbName);
            }
        }
    }

    /**
     * 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。
     *
     * @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会调用此方法获取数据库。
     *
     * @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;
    }
}

然后通过如下的方法得到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);//写入流
            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);
            }
            //写完后刷新
            outputStream.flush();
            ToastUtil.showLong(XinYiApplication.instance,"复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (inputStream != null) {//关闭流,释放资源
                    inputStream.close();
                }
                if(outputStream!=null){
                    outputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

2.5 建立索引(或者设置唯一属性)

@Entity( indexes = {
        @Index(value = "idCard", unique = true)
})
public class Teacher implements Serializable{
    @Id
    @Property(nameInDb = "tid")
    private Long tid;//主键


    private String idCard;//身份证号码
}

idCard属性被插入一样的值 就会报错。

2.6 @ToMany

一个老师对应多个学生即1:N。

@ToMany 有三种情况,根据需要选用不同的情况。

2.61 referencedJoinProperty 关联

@Entity
public class Teacher implements Serializable {
    @Id
    private Long id;//主键
    private String name;
    @Unique
    private Long idCard;//身份证号码
    
    //与上面的属性没得关系。referencedJoinProperty 与Student里面的idCard 相关。且是主键关联
    @ToMany(referencedJoinProperty = "idCard")
    private List students;
}

student表:

@Entity
public class Student {
   @Id
   public Long id;
   private String name;

   //Teacher的主键(必须是主键,)
   public Long idCard;
   
}

总结:A:B=1:N 假如是通过referencedJoinProperty 关联的话,B里面有A的主键,属性不同没得关系..A里面的referencedJoinProperty 指向B中的A的主键表示的属性。。例如上面的B_idCard.

2.62 joinProperties 关联

teacher类的定义:

@Entity
public class Teacher  {
    @Id
    private Long id;
    private String teacherName;

    //一下的是一体的
    @NotNull
    private Long tidCard;
    @ToMany(joinProperties = {
            @JoinProperty(name = "tidCard", referencedName = "tidCard")
    })
    private List students;

student类的定义:

@Entity
public class Student {
    @Id
    private Long id;
    @NotNull
    private Long tidCard;

joinProperties 属性将Teacher 里面的独一的非主键,当做Student的外键。referencedJoinProperty 关联 必须是主键作为Student的外键。

@ToMany注意:

通过查找teacher,能获得List。实际上当你查找得到一个Teacher 对象的时候,其实List这个时候为空的。只有当你调用getStudents()的时候才会进行查找。。这个与@ToOne的差别。

greendao的总结就到这里,以后看博客真的要先看英文文档。

你可能感兴趣的:(Android greendao实践教程)