• 使用GreenDao创建表、关联表(一对一,一对多,多对多)、CURD、升级数据库等操作


    应用场景:从照片中找出包含有用户人脸的照片,并保存该照片中的人脸特征、使用该特征和用户人脸特征对比,满足条件,照片就保存到该用户表里

    一、创建表
    GreenDao托管地址:https://github.com/greenrobot/greenDAO

    官方文档:http://greenrobot.org/greendao/documentation/updating-to-greendao-3-and-annotations

    添加GreenDao插件到项目中 

    classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
    buildscript {

    repositories {
    ..............................................................
    }
    dependencies {
    .............................................................
    classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'

    }
    }
    添加依赖到模块中

    apply plugin: 'org.greenrobot.greendao' // apply plugin

    dependencies {
    ............
    implementation 'org.greenrobot:greendao:3.2.2' // add library
    }
    实体类

    @Entity
    public class PortraitPhoto {

    @Id(autoincrement = true)
    //id参数类型要使用Long,不然保存后id一直为0
    private Long id;
    private String name;
    private String path;
    private int faceCount;
    private String sdCardId;
    //一对多的关系,一张照片可能有多个人,所以会有多个人脸特征(一张脸一个特征)
    @ToMany(referencedJoinProperty = "portraitPhotoId")
    List<Feature> featureList;
    }
     

    @Entity
    public class Feature {
    @Id(autoincrement = true)
    private Long id;
    private Long portraitPhotoId;
    private byte[] features;
    }
    用于保存用户id ,因为用户id是唯一的,所以我用它来做UserPhoto表的主键,也就是userId,下面保存多对多关系时会用到


    @Entity public class UserPhoto {
    @Id private Long id;
    //照片和用户是多对多的关系
    @ToMany
    @JoinEntity(entity = PhotoJoinUser.class, sourceProperty = "userId", targetProperty = "portraitPhotoId")
    private List<PortraitPhoto> portraitphotoList;
    多对多的关系,需要建立中间表,一张照片里面可能有多个用户,一个用户可以出现多张照片里面 

    @Entity
    public class PhotoJoinUser {

    @Id
    private Long id;
    private Long portraitPhotoId;
    private Long userId;
    }
     

    实体类创建好之后,点击AndroidStudio工具栏 Build - Make project

    初始化

    //UpgradeHelper 是升级数据库相关的一个类,继承DaoMaster.OpenHelper
    UpgradeHelper openHelper = new UpgradeHelper(context, NAME,null);
    final Database db = openHelper.getWritableDb();
    mDaoSession = new DaoMaster(db).newSession();

    运行一下,就能创建表了,如下图(这是添加数据后,可以看看表的结构)


    UserPhoto
    二、保存
    mPortraitPhotoDao = mDaoSession.getPortraitPhotoDao();
    mFeatureDao = mDaoSession.getFeatureDao();


    for (PortraitPhoto portraitPhoto : portraitPhotoList) {
    ......................

    if (portraitPhoto.getFaceCount() == NOBODY) {
    continue;
    }
    Bitmap bitmap = BitmapFactory.decodeFile(portraitPhoto.getPath());
    if (mPrtekIIS == null || bitmap == null) {
    continue;
    }

    final int width = bitmap.getWidth() & ~1;
    final int height = bitmap.getHeight() & ~1;
    Image image = new AshmemImage(ImageFormat.NV21, width, height);
    image.setBitmap(bitmap, new Rect(0, 0, width, height));
    //查找图片中是否有人
    List<Person> persons = mPrtekIIS.findPersons(image);

    if (persons == null || persons.isEmpty()) {
    portraitPhoto.setFaceCount(NOBODY);

    //保存没有人脸的照片
    mPortraitPhotoDao.insert(portraitPhoto);
    continue;
    }
    portraitPhoto.setFaceCount(persons.size());
    //保存有人脸的照片
    mPortraitPhotoDao.insert(portraitPhoto);
    //保存特征
    for (Person person : persons) {
    FaceFeature facefeature = person.getFace().getFeature();

    if (facefeature == null) {
    continue;
    }

    Feature feature = new Feature();
    feature.setFeatures(facefeature.serialize());
    //一对多关系保存方式
    feature.setPortraitPhotoId(portraitPhoto.getId());
    mFeatureDao.insert(feature);

    }
    portraitPhotos.add(portraitPhoto);
    }
    多对多关系保存

    //照片和用户已经保存过了,所以只要在第三张绑定一下Id就可以了
    PhotoJoinUser photoJoinUser = new PhotoJoinUser();
    //照片的id
    photoJoinUser.setPortraitPhotoId(portraitPhoto.getId());
    //用户的id
    photoJoinUser.setUserId(user.getUserId());
    //保存
    mDaoSession.insert(photoJoinUser);
    GreenDao CURD方法支持多种参数类型

    insertInTx()//保存 集合或数组、可变参数

    insertOrReplace()//如果数据库中不存在这一条信息就保存,否则替换
    三、更新
    update()//更新很简单,项目也没有使用,所以就不举例子说明了
    四、删除
    GreenDao不支持删除级联,有关联表的数据需要查询后再逐一删除,例如,删除了一张照片,照片里有用户(包含特征)。但是关联特征表里的数据不会删掉

    public void deletePhoto(List<PortraitPhoto> photos) {
    if (photos == null || photos.isEmpty()) {
    return;
    }
    final PhotoJoinUserDao photoJoinUserDao = mDaoSession.getPhotoJoinUserDao();
    final FeatureDao featureDao = mDaoSession.getFeatureDao();
    final PortraitPhotoDao portraitPhotoDao = mDaoSession.getPortraitPhotoDao();

    for (PortraitPhoto photo : photos) {
    //通过条件(照片id)从中间表删除
    photoJoinUserDao.queryBuilder()
    .where(PhotoJoinUserDao.Properties.PortraitPhotoId.eq(photo.getId()))
    .buildDelete()
    .executeDeleteWithoutDetachingEntities();
    //获取该照片所有特征
    final List<Feature> featureList = photo.getFeatureList();

    if (featureList != null) {
    //删除
    featureDao.deleteInTx(featureList);
    }
    }
    //最后删除该照片集合(其实里边就一张,只是通过条件查询时返回List<PortraitPhoto>)
    portraitPhotoDao.deleteInTx(photos);
    }
    五、查询
    final List<PortraitPhoto> dbPhotoList = mPortraitPhotoDao.queryBuilder()
    .where(PortraitPhotoDao.Properties.SdCardId.eq(mSdcardId))
    .list();
    六、升级
    //在模块的Build.grade文件添加、
    greendao{
    schemaVersion 2//修改版本号,即可升级
    }
     GreenDao数据库升级默认是不会迁移数据的,之前的数据将会丢失。下面是在stackoverflow网站找到了解决方案,也写了相关的作者和编辑人员

    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.support.annotation.NonNull;
    import android.text.TextUtils;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import org.greenrobot.greendao.AbstractDao;
    import org.greenrobot.greendao.database.Database;
    import org.greenrobot.greendao.database.StandardDatabase;
    import org.greenrobot.greendao.internal.DaoConfig;



    /**
    * Createdby PedroOkawa and modified by MBH on 16/08/16.
    */
    public final class MigrationHelper {

    public static void migrate(SQLiteDatabase sqliteDatabase, Class<? extends AbstractDao<?, ?>>... daoClasses) {
    StandardDatabase db = new StandardDatabase(sqliteDatabase);
    generateNewTablesIfNotExists(db, daoClasses);
    generateTempTables(db, daoClasses);
    dropAllTables(db, true, daoClasses);
    createAllTables(db, false, daoClasses);
    restoreData(db, daoClasses);
    }

    public static void migrate(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
    generateNewTablesIfNotExists(db, daoClasses);
    generateTempTables(db, daoClasses);
    dropAllTables(db, true, daoClasses);
    createAllTables(db, false, daoClasses);
    restoreData(db, daoClasses);
    }

    private static void generateNewTablesIfNotExists(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
    reflectMethod(db, "createTable", true, daoClasses);
    }

    private static void generateTempTables(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
    for (int i = 0; i < daoClasses.length; i++) {
    DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
    String tableName = daoConfig.tablename;
    String tempTableName = daoConfig.tablename.concat("_TEMP");
    StringBuilder insertTableStringBuilder = new StringBuilder();
    insertTableStringBuilder.append("CREATE TEMP TABLE ").append(tempTableName);
    insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");
    db.execSQL(insertTableStringBuilder.toString());
    }
    }

    private static void dropAllTables(StandardDatabase db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
    reflectMethod(db, "dropTable", ifExists, daoClasses);
    }

    private static void createAllTables(StandardDatabase db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
    reflectMethod(db, "createTable", ifNotExists, daoClasses);
    }

    /**
    * dao class already define the sql exec method, so just invoke it
    */
    private static void reflectMethod(StandardDatabase db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
    if (daoClasses.length < 1) {
    return;
    }
    try {
    for (Class cls : daoClasses) {
    Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);
    method.invoke(null, db, isExists);
    }
    } catch (NoSuchMethodException e) {
    e.printStackTrace();
    } catch (InvocationTargetException e) {
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    }
    }

    private static void restoreData(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
    for (int i = 0; i < daoClasses.length; i++) {
    DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
    String tableName = daoConfig.tablename;
    String tempTableName = daoConfig.tablename.concat("_TEMP");
    // get all columns from tempTable, take careful to use the columns list
    List<String> columns = getColumns(db, tempTableName);
    ArrayList<String> properties = new ArrayList<>(columns.size());
    for (int j = 0; j < daoConfig.properties.length; j++) {
    String columnName = daoConfig.properties[j].columnName;
    if (columns.contains(columnName)) {
    properties.add(columnName);
    }
    }
    if (properties.size() > 0) {
    final String columnSQL = TextUtils.join(",", properties);

    StringBuilder insertTableStringBuilder = new StringBuilder();
    insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
    insertTableStringBuilder.append(columnSQL);
    insertTableStringBuilder.append(") SELECT ");
    insertTableStringBuilder.append(columnSQL);
    insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
    db.execSQL(insertTableStringBuilder.toString());
    }
    StringBuilder dropTableStringBuilder = new StringBuilder();
    dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
    db.execSQL(dropTableStringBuilder.toString());
    }
    }

    private static List<String> getColumns(StandardDatabase db, String tableName) {
    List<String> columns = null;
    Cursor cursor = null;
    try {
    cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);
    if (null != cursor && cursor.getColumnCount() > 0) {
    columns = Arrays.asList(cursor.getColumnNames());
    }
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    if (cursor != null)
    cursor.close();
    if (null == columns)
    columns = new ArrayList<>();
    }
    return columns;
    }

    }
    前面初始化时,用到的 UpgradeHelper 类,在onUpgrade方法更新

    public class UpgradeHelper extends DaoMaster.OpenHelper {
    public UpgradeHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
    super(context, name, factory);
    }

    @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    MigrationHelper.migrate(db, PortraitPhotoDao.class, FeatureDao.class, PhotoJoinUserDao.class,
    UserPhotoDao.class);
    }
    }
     
    ————————————————

    原文链接:https://blog.csdn.net/zhanlv/article/details/82425709

  • 相关阅读:
    python --github 刷题
    http://www.rehack.cn/techshare/webbe/php/3391.html
    SQL 百万级数据提高查询速度的方法
    开学收好这 17 种工具 App,让你新学期学习更有效率
    Git文件常见下标符号说明
    TortoiseGit功能介绍
    gitlab图形化使用教程 (mtm推荐)
    gitlab 服务器的搭建与使用全过程(一)
    Git详解之一 Git实战
    Git使用基础篇
  • 原文地址:https://www.cnblogs.com/changyiqiang/p/14775984.html
Copyright © 2020-2023  润新知