One, ORM simple popular science

The so-called ORM, namely Object/Relation Mapping, is convenient for us to operate the relational database in the way of operating objects.

In the course of your normal development, you’re bound to come across SQLite at some point or another. However, when using it, we often need to do a lot of extra work, such as writing SQL statements and parsing query results.

Suppose we have an object that needs to be stored in a database:

@Table
public class Person {
    @Column
    private int id;

    @Check("name! ='Fucker'")
    @Column
    private String name;

    @Default
    @Column
    private double height = 180;

    @Column
    private int age;

    @Default
    @NotNull
    @Column
    private String job = "IT";
}
Copy the code

When we create a table, we need to write the following SQL statement:

create table if not exists Person( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT CHECK(name! ='Fucker'),
    height REAL DEFAULT 180.0,
    age INTEGER,
    job TEXT DEFAULT IT NOT NULL);
Copy the code

And then after the query, we need to iterate over Curcor, and then set it into the object, is that a hassle?

while (cursor.moveToNext()) {
    int nameColumnIndex = cursor.getColumnIndex("filedName");
    String value = cursor.getString(nameColumnIndex);
}
Copy the code

Accidentally MISspelled SQL, or cursor take field field name write wrong, GG ah!

As a result, various ORM frameworks came out, through annotations and reflection to create SQL tables, parsing cursor into objects, are automated, which is greatly convenient for us lazy people.

However, the ORM framework is now mostly in writing query statements, feeling a bit excessive encapsulation, sometimes, the use of ORM framework to do conditional query, even better than their own to write query SQL!

In order to solve this problem, I encapsulated a set of ORM framework of my own, referring to Guava’s string operation library Fluent chain interface idea, will write query statement a little more convenient, not only to reduce the problem that we write native SQL statements easily misspelled, but also unlike some ORM framework is not convenient to do complex conditional query.

Of course, the framework is still being improved (indexes and multi-table associations have not been added for the time being), so if you think there is something unreasonable in my following encapsulation, please feel free to discuss with me!

Second, the framework of the test class:

Test scenario:

  1. Execute custom Sql

  2. Table operation: create table, delete table, backup, existence judgment

  3. insert

  4. delete

  5. The query

  6. update

  7. The transaction

package com.che.baseutil.sqlite;

import android.app.Application;

import com.che.base_util.LogUtil;
import com.che.baseutil.BuildConfig;
import com.che.baseutil.table.Person;
import com.che.baseutil.table.Teacher;
import com.che.fast_orm.DBHelper;
import com.che.fast_orm.helper.DBException;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;

import java.util.ArrayList;
import java.util.List;

import static com.google.common.truth.Truth.assertThat;

/** ** ** /
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, manifest = "src/main/AndroidManifest.xml", packageName = "com.che.baseutil", resourceDir = "res")
public class DBTestClient {

    private DBHelper dbHelper;// Database helper classes

    @Before
    public void setUp(a) throws DBException {
        ShadowLog.stream = System.out;
        Application application = RuntimeEnvironment.application;
        dbHelper = new DBHelper(application, "mydb".1);
        / / delete table
        dbHelper.drop(Person.class);
        / / create a table
        dbHelper.create(Person.class);
        // Initialize the data for later operation
        initData();
    }

    /** * insert */
    public void initData(a) {
        try {
            // Insert more data
            List<Person> persons = new ArrayList<>();
            persons.add(new Person("Fishyer".23));
            persons.add(new Person("Stay".23));
            persons.add(new Person("Ricky"));
            persons.add(new Person("Stay".23));
            persons.add(new Person("Fuck".24));
            persons.add(new Person("Albert"));
            dbHelper.insertAll(persons);

            // Insert single data
            Person untitled = new Person();
            untitled.setAge(21);
            untitled.setHeight(200);
            dbHelper.insert(untitled);
        } catch (DBException e) {
            LogUtil.print("Database exception:"+ e.getMessage()); }}/** * custom Sql */
    @Test
    public void testSql(a) throws DBException {
        dbHelper.execSQL("drop table if exists Person");
        dbHelper.execSQL("create table if not exists Person(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT,age INTEGER DEFAULT 100)");
        dbHelper.execSQL("insert into Person (age) values (21)");
        dbHelper.execSQL("insert into Person (name,age) values ('Fishyer',23)");
    }

    /** ** table operation */
    @Test
    public void testTable(a) throws DBException {
        //删除表: drop table if exists Teacher
        dbHelper.drop(Teacher.class);
        Select count(*) from sqlite_master where type='table' and name='Teacher'
        assertThat(dbHelper.isExist(Teacher.class)).isEqualTo(false);
        Create table if not exists Teacher(ID INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,age INTEGER,course TEXT)
        dbHelper.create(Teacher.class);
        // Assert that the table exists:
        assertThat(dbHelper.isExist("Teacher")).isEqualTo(true);
    }

    /** * transaction */
    @Test
    public void testTransaction(a) throws DBException {
        Person person = new Person("Fishyer".23);
        dbHelper.beginTransaction();
        for (int i = 0; i < 100; i++) {
            //insert or replace into Person (name,height,age) values ('Fishyer',180.0,23)
            dbHelper.insert(person);
        }
        dbHelper.endTransaction();
    }

    /** * delete */
    @Test
    public void testDelete(a) throws DBException {
        Delete from Person where name='Stay' and height=180.0 and age=-1;
        dbHelper.deleteObj(new Person("Stay"));

        // Delete all data :delete from Person
        dbHelper.deleteAll(Person.class);

        Delete from Person where name='Stay'
        dbHelper.delete(Person.class).where("name=Stay").execute();
    }

    @Test
    public void testQuery(a) throws DBException {
        Select * from Person
        dbHelper.queryAll(Person.class);

        Select * from Person where name='Stay'
        dbHelper.queryObj(new Person("Stay"));
    }

    @Test
    public void testSelect(a) throws DBException {
        Select * from Person where age>='21' order by name
        dbHelper.select(Person.class).whereInt("age>=21").orderBy("name").query();

        Select * from Person order by age desc
        dbHelper.select(Person.class).where("name=Stay").append("order by id").desc().query();

        Select * from Person where age='23' order by name
        dbHelper.select(Person.class).whereInt("age=23").orderBy("id").query();

        Select distinct * from Person order by age desc
        dbHelper.distinct(Person.class).whereInt("age=23").orderBy("id").query();
    }

    @Test
    public void testBackup(a) throws DBException {
        Create table Student_bak as select *from Person
        dbHelper.bak(Person.class);

        // Query backup: select * from Student_bak
        dbHelper.queryBak(Person.class);
    }

    @Test
    public void testUpdate(a) throws DBException {
        Update Person set age=99 where name='Fishyer'
        dbHelper.update(Person.class).setInt("age=99").where("name=Fishyer").execute();

        dbHelper.queryAll(Person.class);
    }

    @Test
    public void testIndex(a) throws DBException {
        // TODO:16/9/17 Add an index
    }

    @Test
    public void testMap(a) throws DBException {
        // TODO:16/9/17 Add a multi-table association}}Copy the code

Three, ORM framework packaging road:

This framework is not so much a design as a constant refactoring. I started as a tool class, and then expanded and optimized it, and it became a framework.

1. The ORM tools

public class DBHelper extends SQLiteOpenHelper {

    /** * constructor, which must implement **@paramContext *@paramName Database name *@paramVersion Current database version */
    public DBHelper(Context context, String name, int version) {
        super(context, name, null, version);
    }

    // Called when the database is created for the first time
    @Override
    public void onCreate(SQLiteDatabase db) {}// When the database needs to be modified, the Android system actively calls this method.
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}// Basic modify command
    public void execSQL(String sql) throws DBException {
        try {
            sql += ";";
            LogUtil.print(sql);
            getWritableDatabase().execSQL(sql);
        } catch (Exception e) {
            e.printStackTrace();
            throw newDBException(e.getMessage()); }}// Basic query commands
    public Cursor rawQuery(String sql) throws DBException {
        Cursor cursor = null;
        try {
            sql += ";";
            LogUtil.print(sql);
            cursor = getReadableDatabase().rawQuery(sql, null);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(e.getMessage());
        }
        return cursor;
    }

    /** * table operation command */
    public void create(Class
        clazz) throws DBException {
        String createSql = SqlGenerater.create(clazz);
        execSQL(createSql);
    }

    public void drop(Class
        clazz) throws DBException {
        String dropSql = SqlGenerater.drop(clazz);
        execSQL(dropSql);
    }

    public <T> void bak(Class<T> clazz) throws DBException {
        String bakSql = SqlGenerater.bak(clazz);
        execSQL(bakSql);
    }

    public <T> boolean isExist(Class<T> clazz) throws DBException {
        return isExist(ReflectHelper.getTableName(clazz));
    }

    public boolean isExist(String tableName) throws DBException {
        Cursor cursor = rawQuery("select count(*) from sqlite_master where type='table' and name='" + tableName + "'");
        if (cursor.moveToNext()) {
            int count = cursor.getInt(0);
            if (count > 0) {
                return true; }}return false;
    }

    /** * add */
    public <T> void insert(T t) throws DBException {
        String insertSql = SqlGenerater.insert(t);
        execSQL(insertSql);
    }

    public <T> void insertAll(List<T> list) throws DBException {
        getWritableDatabase().beginTransaction();
        for (T t : list) {
            insert(t);
        }
        getWritableDatabase().setTransactionSuccessful();
        getWritableDatabase().endTransaction();
    }

    /** * delete */
    public <T> void deleteObj(T t) throws DBException {
        String whereSql = SqlGenerater.deleteObj(t);
        execSQL(whereSql);
    }

    public <T> void deleteAll(Class<T> clazz) throws DBException {
        String deleteAllSql = SqlGenerater.deleteAll(clazz);
        execSQL(deleteAllSql);
    }

    /** * query */
    public <T> List<T> queryObj(T t) throws DBException {
        String whereSql = SqlGenerater.queryObj(t);
        Cursor cursor = rawQuery(whereSql);
        return (List<T>) ReflectHelper.parseCursor(cursor, t.getClass());
    }

    public <T> List<T> queryAll(Class<T> clazz) throws DBException {
        String queryAllSql = SqlGenerater.queryAll(clazz);
        Cursor cursor = rawQuery(queryAllSql);
        return ReflectHelper.parseCursor(cursor, clazz);
    }

    public <T> List<T> queryBak(Class<T> clazz) throws DBException {
        String selectAllSql = SqlGenerater.queryBak(clazz);
        Cursor cursor = rawQuery(selectAllSql);
        return ReflectHelper.parseCursor(cursor, clazz);
    }

    /** * create the linker editor */
    / / query
    public <T> ConnectBuilder<T> select(Class<T> clazz) throws DBException {
        return new ConnectBuilder(this, clazz, "select * from " + ReflectHelper.getTableName(clazz));
    }

    // go to query again
    public <T> ConnectBuilder<T> distinct(Class<T> clazz) throws DBException {
        return new ConnectBuilder(this, clazz, "select distinct * from " + ReflectHelper.getTableName(clazz));
    }

    / / delete
    public <T> ConnectBuilder<T> delete(Class<T> clazz) throws DBException {
        return new ConnectBuilder(this, clazz, "delete from " + ReflectHelper.getTableName(clazz));
    }

    / / modify
    public <T> ConnectBuilder<T> update(Class<T> clazz) throws DBException {
        return new ConnectBuilder(this, clazz, "update " + ReflectHelper.getTableName(clazz));
    }

    /** * linker editor - executes with no return value */
    public <T> void execute(ConnectBuilder<T> builder) throws DBException {
        execSQL(builder.sql);
    }

    /** * editor - query, return value */
    public <T> List<T> query(ConnectBuilder<T> builder) throws DBException {
        Cursor cursor = rawQuery(builder.sql);
        return ReflectHelper.parseCursor(cursor, builder.clazz);
    }

    /** * start transaction */
    public void beginTransaction(a) {
        getReadableDatabase().beginTransaction();
    }

    /** * close transaction */
    public void endTransaction(a) { getReadableDatabase().setTransactionSuccessful(); getReadableDatabase().endTransaction(); }}Copy the code

2.SQL statement encapsulation

In the above tool class, you can see my encapsulation, mainly is to create the PROCESS of SQL statement encapsulation, mainly from two aspects:

  1. SqlGenerater: Sql statement generator

This class generates a SQL statement based on the class information and object information, and gives it to DBHelper for processing. It is suitable for some stereotyped SQL, such as create and INSERT


2.ConnectBuilder

This class is mainly for the convenience of writing query SQL, where, and, set, etc., through the chain call concatenation, synthesis of an SQL, and write native SQL is similar, but as far as possible to avoid writing native SQL accidentally where less space and other problems

Sql statement generator:

public class SqlGenerater {

    public final static String BAK_SUFFIX = "_bak";// Backup suffix

    Create table Student(ID INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age TEXT) */
    public static String create(Class
        clazz) {
        TableWrapper wrapper = ReflectHelper.parseClass(clazz);
        Create table Student(id INTEGER PRIMARY KEY AUTOINCREMENT,
        StringBuilder sb = new StringBuilder("create table if not exists " + wrapper.name);
        (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age TEXT)
        sb.append(TypeConverter.zipNameType(wrapper));
        return sb.toString();
    }

    /** * drop table if exists Student; * /
    public static String drop(Class
        clazz) {
        StringBuilder sb = new StringBuilder("drop table if exists " + ReflectHelper.getTableName(clazz));
        return sb.toString();
    }

    Insert or replace into Student (name,age) values ('Fishyer',23) */
    public static <T> String insert(T t) {
        TableWrapper wrapper = ReflectHelper.parseObject(t);
        // insert into Student
        StringBuilder sb = new StringBuilder("insert or replace into " + wrapper.name + "");
        // splice :(name,age)
        sb.append(TypeConverter.zipName(wrapper));
        // splice: values
        sb.append(" values ");
        // splice ('Fishyer',23)
        sb.append(TypeConverter.zipValue(wrapper));
        return sb.toString();
    }

    Select * from Student */ select * from Student
    public static String queryAll(Class
        clazz) {
        StringBuilder sb = new StringBuilder("select * from " + ReflectHelper.getTableName(clazz));
        return sb.toString();
    }

    /** * delete from Student */
    public static String deleteAll(Class
        clazz) {
        StringBuilder sb = new StringBuilder("delete from " + ReflectHelper.getTableName(clazz));
        return sb.toString();
    }

    Select * from Student where name='Fishyer' and age=23 */
    public static <T> String queryObj(T t) {
        TableWrapper wrapper = ReflectHelper.parseObject(t);
        // select * from Student
        StringBuilder sb = new StringBuilder("select * from " + wrapper.name);
        Where name='Fishyer' and age=23
        sb.append(TypeConverter.zipConnNameValue(wrapper));
        return sb.toString();
    }

    Delete from Student where name='Fishyer' and age=23 */
    public static <T> String deleteObj(T t) {
        TableWrapper wrapper = ReflectHelper.parseObject(t);
        // select * from Student
        StringBuilder sb = new StringBuilder("delete from " + wrapper.name);
        Where name='Fishyer' and age=23
        sb.append(TypeConverter.zipConnNameValue(wrapper));
        return sb.toString();
    }

    Create table Student2 as select *from Student */
    public static <T> String bak(Class<T> clazz) {
        String table = ReflectHelper.getTableName(clazz);
        String tableBak = table + BAK_SUFFIX;
        StringBuilder sb = new StringBuilder("create table " + tableBak + " as select *from " + table);
        return sb.toString();
    }

    Select * from Student */ select * from Student
    public static String queryBak(Class
        clazz) {
        StringBuilder sb = new StringBuilder("select * from " + ReflectHelper.getTableName(clazz) + BAK_SUFFIX);
        returnsb.toString(); }}Copy the code

Connecter editor:

public class ConnectBuilder<T> {
    public DBHelper dbHelper;// Use to call terminating concatenators: query and execute
    public Class<T> clazz;// Use to parse Cursor
    public String sql;

    public ConnectBuilder(DBHelper dbHelper, Class<T> clazz, String sql) {
        this.dbHelper = dbHelper;
        this.clazz = clazz;
        this.sql = sql;
    }

    /** ** where where concatenate * 

* 1, the default where comparator is =, and the difference between where and whereInt is that the values are quoted */

public ConnectBuilder<T> where(String s) { return where(s, "="); } public ConnectBuilder<T> where(String s, String operation) { this.sql = sql + (" where " + TypeConverter.addQuote(s, operation)); return this; } public ConnectBuilder<T> whereInt(String s) { this.sql = sql + (" where " + s); return this; } /** * and 连接符 */ public ConnectBuilder<T> and(String s) { return and(s, "="); } public ConnectBuilder<T> and(String s, String operation) { this.sql = sql + (" and " + TypeConverter.addQuote(s, operation)); return this; } public ConnectBuilder<T> andInt(String s) { this.sql = sql + (" and " + s); return this; } /** * set connecter */ public ConnectBuilder<T> set(String s) { return where(s, "="); } public ConnectBuilder<T> set(String s, String operation) { this.sql = sql + (" set " + TypeConverter.addQuote(s, operation)); return this; } public ConnectBuilder<T> setInt(String s) { this.sql = sql + (" set " + s); return this; } /** * order by 连接符 */ public ConnectBuilder<T> orderBy(String field) { this.sql = sql + (" order by " + field); return this; } /** * desc 连接符 */ public ConnectBuilder<T> desc(a) { this.sql = sql + (" desc"); return this; } /** * the append connector *

* represents a space */

public ConnectBuilder<T> append(String s) { this.sql = sql + ("" + s); return this; } /** * Execute Sql statement, query, return value **@return* / public List<T> query(a) throws DBException { return dbHelper.query(this); } /** * Execute Sql statement, non-query, no return value **@return* / public void execute(a) throws DBException { dbHelper.execute(this); }}Copy the code

3. Reflection AIDS

In order for the SQL Generater above to generate the correct SQL, we need to use annotations and reflection.

We annotate a class (such as Person above) with the parameters we need to create a table from that class.

With reflection, we can get these parameters at run time and hand them to SqlGenerater.

public class ReflectHelper {

    /** * Direct reflection, get the field value */
    private static <T> Object getFieldValue(T t, Field field) {
        // TODO:16/9/15 How do I automatically force the return value to fieldType here? Solve!!
        Object value = null;
        try {
            field.setAccessible(true);
            value = field.get(t);
            field.setAccessible(false);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return value;
    }

    /** * parse the database cursor **@param cursor
     * @param clazz
     * @return* /
    public static <T> List<T> parseCursor(Cursor cursor, Class<T> clazz) {
        List<T> list = new ArrayList<>();
        try {
            TableWrapper wrapper = ReflectHelper.parseClass(clazz);
            while (cursor.moveToNext()) {
                T t = clazz.newInstance();
                int pos = 0;
                for(String filedName : wrapper.filedList) { Class<? > type = wrapper.typeList.get(pos); Object value = getCursorValue(cursor, filedName, type); Field field = clazz.getDeclaredField(filedName); field.setAccessible(true);
                    field.set(t, value);
                    field.setAccessible(false);
                    pos++;
                }
                LogUtil.print("-- -- >." + t.toString());
                list.add(t);
            }
            cursor.close();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return list;
    }

    /** * Parses information about classes or objects */
    private static <T> TableWrapper parse(Class
        clazz, T t) {
        List<String> filedList = new ArrayList<>();/ / the field nameList<Class<? >> typeList =new ArrayList<>();// Field type
        List<String> constraintList = new ArrayList<>();// Field constraints (a column may have more than one constraint)
        List<Object> valueList = new ArrayList<>();/ / field values
        // Determine if there are table annotations
        if(! clazz.isAnnotationPresent(Table.class)) {throw new RuntimeException(clazz.getName() + "No table annotations added");
        }

        int column = 0;
        // Iterate over all fields
        for (Field field : clazz.getDeclaredFields()) {
            // Determine if there are column annotations
            if (field.isAnnotationPresent(Column.class)) {
                column++;
                String fieldName = ReflectHelper.getColumnName(field); // Get the field nameClass<? > fieldType = field.getType();// Get the field type
                Object fieldValue = t == null ? null : getFieldValue(t, field);// Get the field value

                // When not created, the ID field is ignored
                if(t ! =null && fieldName.toLowerCase().equals("id".toLowerCase())) {
                    continue;
                }

                // Add field constraints when creating a table
                if (t == null) {
                    addConstraint(clazz, field, constraintList);
                }

                // Omit empty fields when inserting data
                if(t ! =null && fieldValue == null) {
                    continue;
                }

                // Add field name, field type, and field value to the listfiledList.add(fieldName); typeList.add(fieldType); valueList.add(fieldValue); }}if (column == 0) {
            throw new RuntimeException(clazz.getName() + "No column annotations have been added to the table");
        }
        if(t ! =null && filedList.isEmpty()) {
            throw new RuntimeException(clazz.getName() + "All columns of object in table are empty");
        }
        return new TableWrapper(getTableName(clazz), filedList, typeList, constraintList, valueList);
    }

    /** * get the table name **@param clazz
     * @return* /
    public static String getTableName(Class
        clazz) {
        Table annotation = clazz.getAnnotation(Table.class);
        String value = annotation.value();
        return TextUtils.isEmpty(value) ? clazz.getSimpleName() : value;

    }

    /** * get column name **@param field
     * @return* /
    private static String getColumnName(Field field) {
        Column annotation = field.getAnnotation(Column.class);
        String value = annotation.value();
        return TextUtils.isEmpty(value) ? field.getName() : value;
    }

    /** * Add field constraint **@param clazz
     * @param field
     * @param list
     */
    private static <T> void addConstraint(Class<T> clazz, Field field, List<String> list) {
        StringBuffer sb = new StringBuffer();
        // Iterate over all annotations for the field
        for (Annotation item : field.getDeclaredAnnotations()) {
            if (item instanceof NotNull) {
                sb.append(Constraint.NOT_NULL);
            } else if (item instanceof Default) {
                String value = getDefaultValue(clazz, field);
                sb.append(Constraint.DEFAULT + "" + value);
            } else if (item instanceof Unique) {
                sb.append(Constraint.UNIQUE);
            } else if (item instanceof Check) {
                Check annotation = field.getAnnotation(Check.class);
                String value = annotation.value();
                sb.append(Constraint.CHECK + "(" + value + ")");
            } else {
                sb.append("");
            }
        }
        list.add(sb.toString());
    }

    /** * gets the default value for the column **@param clazz
     * @param field
     * @return* /
    private static <T> String getDefaultValue(Class<T> clazz, Field field) {
        try {
            T t = clazz.newInstance();
            return getFieldValue(t, field).toString();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("Obtaining column default value exception");
    }

    /** * Parsing object information */
    public static <T> TableWrapper parseObject(T t) {
        return parse(t.getClass(), t);
    }

    /** * Parses the class information */
    public static TableWrapper parseClass(Class
        clazz) {
        return parse(clazz, null);
    }

    /** * Parses the list information */
    public static <T> List<TableWrapper> parseList(List<T> list) {
        List<TableWrapper> wrappers = new ArrayList<>();
        for (T t : list) {
            wrappers.add(parse(t.getClass(), t));
        }
        return wrappers;
    }

    /** * Get the value of database Cursor * 

* for example :'Stay',23 */

private static Object getCursorValue(Cursor cursor, String filedName, Class type) { while (cursor.moveToNext()) { int nameColumnIndex = cursor.getColumnIndex("filedName"); String value = cursor.getString(nameColumnIndex); } / / text if (type == String.class) { return cursor.getString(cursor.getColumnIndex(filedName)); } // TODO:16/9/15 fetch integer, if the data store is null, this will automatically become 0, a problem! / / integer else if (type == int.class) { return cursor.getInt(cursor.getColumnIndex(filedName)); } else if (type == Integer.class) { return cursor.getInt(cursor.getColumnIndex(filedName)); } else if (type == long.class) { return cursor.getLong(cursor.getColumnIndex(filedName)); } else if (type == Long.class) { return cursor.getLong(cursor.getColumnIndex(filedName)); } else if (type == boolean.class) { int anInt = cursor.getInt(cursor.getColumnIndex(filedName)); return anInt == 0 ? false : true; } else if (type == Boolean.class) { int anInt = cursor.getInt(cursor.getColumnIndex(filedName)); return anInt == 0 ? false : true; } / / real else if (type == float.class) { return cursor.getFloat(cursor.getColumnIndex(filedName)); } else if (type == Float.class) { return cursor.getFloat(cursor.getColumnIndex(filedName)); } else if (type == double.class) { return cursor.getDouble(cursor.getColumnIndex(filedName)); } else if (type == Double.class) { return cursor.getDouble(cursor.getColumnIndex(filedName)); } // Input form else { return " BLOB"; }}}Copy the code

4. Other auxiliary classes

Table information packaging class:

This is essentially resolving a Class through ReflectHelper into this TableWrapper, which is the carrier of the parameters that write the SQL

public class TableWrapper {
    public String name;/ / the name of the class
    public List<String> filedList;/ / the field name
    publicList<Class<? >> typeList;// Field type
    public List<String> constraintList;// Field constraints
    public List<Object> valueList;/ / field values

    public TableWrapper(String name, List
       
         filedList, List
        
         > typeList, List
         
           constraintList, List
           valueList)
         
        >
        {
        this.name = name;
        this.filedList = filedList;
        this.typeList = typeList;
        this.constraintList = constraintList;
        this.valueList = valueList; }}Copy the code

Type converter:

Since the format of the parameters of different SQL commands is different, this is to facilitate the conversion from the field of the class to the column of the table

public class TypeConverter {

    //wrapper --> (name,age)
    public static String zipName(TableWrapper wrapper) {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        for (int i = 0; i < wrapper.filedList.size(); i++) {
            String filed = wrapper.filedList.get(i);
            sb.append(filed);
            if(i ! = wrapper.filedList.size() -1) {
                sb.append(",");
            }
        }
        sb.append(")");
        return sb.toString();
    }

    //wrapper --> ('Fishyer',23)
    public static String zipValue(TableWrapper wrapper) {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        for (int j = 0; j < wrapper.filedList.size(); j++) { Class<? > type = wrapper.typeList.get(j); Object value = wrapper.valueList.get(j); sb.append(TypeConverter.getInsertValue(type, value));if(j ! = wrapper.typeList.size() -1) {
                sb.append(",");
            }
        }
        sb.append(")");
        return sb.toString();
    }

    //wrapper --> (name TEXT NOT NULL, age TEXT)
    public static String zipNameType(TableWrapper wrapper) {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        for (int i = 0; i < wrapper.filedList.size(); i++) {
            String filed = wrapper.filedList.get(i);
            String type = TypeConverter.getCreateType(filed, wrapper.typeList.get(i));
            String constraint = wrapper.constraintList.get(i);
            sb.append(filed + type + constraint);
            if(i ! = wrapper.filedList.size() -1) {
                sb.append(",");
            }
        }
        sb.append(")");
        return sb.toString();
    }

    //wrapper --> where name='Fishyer' and age=23
    public static String zipConnNameValue(TableWrapper wrapper) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < wrapper.filedList.size(); i++) {
            if (i == 0) {
                sb.append(" where ");
            } else {
                sb.append(" and "); } String filed = wrapper.filedList.get(i); Class<? > type = wrapper.typeList.get(i); Object value = wrapper.valueList.get(i); sb.append(filed +"=" + TypeConverter.getInsertValue(type, value));
        }
        return sb.toString();
    }

    /** * Obtain the storage type of the create. * 

* For example, TEXT, INTEGER */

private static String getCreateType(String field, Class type) { / / the primary key if (field.toLowerCase().equals("id".toLowerCase())) { return " INTEGER PRIMARY KEY AUTOINCREMENT"; } / / text if (type == String.class) { return " TEXT"; } / / integer else if (type == int.class) { return " INTEGER"; } else if (type == Integer.class) { return " INTEGER"; } else if (type == long.class) { return " INTEGER"; } else if (type == Long.class) { return " INTEGER"; } else if (type == boolean.class) { return " INTEGER"; } else if (type == Boolean.class) { return " INTEGER"; } / / real else if (type == float.class) { return " REAL"; } else if (type == Float.class) { return " REAL"; } else if (type == double.class) { return " REAL"; } else if (type == Double.class) { return " REAL"; } // Input form else { return " BLOB"; }}/** * get the value stored for Insert *

* for example :'Stay',23 (the main purpose is to put single quotes around String) */

private static String getInsertValue(Class type, Object value) { if (type == String.class) { return "'" + value + "'"; } else if (type == int.class) { return value.toString(); }else { returnvalue.toString(); }}/** * add single quotes to fields *

* Example: Fishyer --> 'Fishyer' */

public static String addQuote(String s, String operation) { String[] strings = s.split(operation); return strings[0] + operation + "'" + strings[1] + "'"; }}Copy the code

Various annotation marks:

@table: Table annotation, default is the class name, you can also customize the Table name

@check: Conditional constraints

Constraint sign constant

public class Constraint {
    public static final String NOT_NULL = " NOT NULL";
    public static final String DEFAULT = " DEFAULT";
    public static final String UNIQUE = " UNIQUE";
    public static final String CHECK = " CHECK";
}
Copy the code