一、简单介绍

SQLDelight 和 SqlBrite 是 Square 公司推出的一个 Android 平台数据库解决方式。

在了解这个两个东西前,必须先得有Andorid的Sqlite的知识(SqliteDatabase and SqliteDataHelper), AutoValue

要分清他们两个的功能:

  • SqlDelight

    是用来把Sql语句生成Java对象的

  • SqlBrite

    才是Sqlite操作。结合Rxjava进行响应式数据库操作。SqlBrite教程

二、SqlDelight

SqlDelight是从SQL语句来生成JAVA对象。

这种优点是,全部SQL语句都位于同一个位置,通过查看SQL语句能够清楚的了解须要实现的功能和数据库的结构。

SqlDelight加入了对SQL语句的编译时验证、表名字和列名字的代码自己主动完毕功能。

让编写SQL语句更加快捷。在编译的时候,依据SQL语句生成Java模型接口和builder来把数据行和Java对象实现转换。

2.1 导包

  1. 在项目build.gradle的dependencies加入:
classpath 'com.squareup.sqldelight:gradle-plugin:0.6.0'
  1. 在module的build.gralde头部加入apply
apply plugin: 'com.squareup.sqldelight'

又一次Sync就可以。

2.2 使用

SqlDelight 能够依据建表的 SQL 语句自己主动生成 Java model interface。interface 的每一个方法就是这张表的每一列。

1. 编写sq语句

在main文件夹创建sqldelight文件夹,然后依照包名创建文件夹, main/sqldelight/com/xxx/xxx/sq文件(一定得是正确的文件夹。不然构建失败)

这里编写创建表和查询的语句;

create table user(
_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER NOT NULL
); -- 其它的语句通过标识符来引用。 在生成的 Java 对象中会包括
-- 一个该标识符的常亮引用这个语句。 -- 查询use表,百分号(%)代表零个、一个或多个数字或字符,||连接两个不同的字符串,得到一个新的字符串。
select_by_name: select * from user;

2. 生成接口Module

编写完毕sql语句之后,make一下moduel。就可以在build/generated/source/sqldelight/包名/看到xxxModule接口文件 (xxx就是你的sq文件的名称)。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbml1Yml0aWFucGluZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

能够看到接口大概是这种。

public interface UserModel {
String TABLE_NAME = "user"; String _ID = "_id"; String NAME = "name"; String AGE = "age"; String CREATE_TABLE = ""
+ "create table user(\r\n"
+ " _id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\r\n"
+ " name TEXT NOT NULL,\r\n"
+ " age INTEGER NOT NULL\r\n"
+ ")"; long _id(); @NonNull
String name(); long age(); interface Creator<T extends UserModel> {
T create(long _id, @NonNull String name, long age);
} final class Mapper<T extends UserModel> implements RowMapper<T> {
private final Factory<T> userModelFactory; public Mapper(Factory<T> userModelFactory) {
this.userModelFactory = userModelFactory;
} @Override
public T map(@NonNull Cursor cursor) {
return userModelFactory.creator.create(
cursor.getLong(0),
cursor.getString(1),
cursor.getLong(2)
);
}
} final class Marshal {
protected final ContentValues contentValues = new ContentValues(); Marshal(@Nullable UserModel copy) {
if (copy != null) {
this._id(copy._id());
this.name(copy.name());
this.age(copy.age());
}
} public ContentValues asContentValues() {
return contentValues;
} public Marshal _id(long _id) {
contentValues.put("_id", _id);
return this;
} public Marshal name(String name) {
contentValues.put("name", name);
return this;
} public Marshal age(long age) {
contentValues.put("age", age);
return this;
}
} final class Factory<T extends UserModel> {
public final Creator<T> creator; public Factory(Creator<T> creator) {
this.creator = creator;
} /**
* @deprecated Use compiled statements (https://github.com/square/sqldelight#compiled-statements)
*/
@Deprecated
public Marshal marshal() {
return new Marshal(null);
} /**
* @deprecated Use compiled statements (https://github.com/square/sqldelight#compiled-statements)
*/
@Deprecated
public Marshal marshal(UserModel copy) {
return new Marshal(copy);
} public SqlDelightStatement select_by_name() {
return new SqlDelightStatement(""
+ "select * from user",
new String[0], Collections.<String>singleton("user"));
} public Mapper<T> select_by_nameMapper() {
return new Mapper<T>(this);
}
}
}

从这个接口能够看到重要的有以下四个类和接口:

  • Mapper

    把 Cursor 映射为 Java 对象

  • Marshal

    把 Java 对象转换为 ContentValues,好方便插入数据库

  • 接口Creator

    里面定义了一个方法create用来创建我们的Model类型(这里用的是泛型T)

  • Factory

    里面包括一个实现了Creator对象的creator,假设有列值须要转换的话还要包括相应的ColumnAdapter。它的构造函数传入Creator和ColumnAdapter这些參数,marshal方法返回Mode的Marshal(通过它的asContentValues获取相应的ContentValues)

3. 定义Bean类

这里利用AtuoValue重写接口,由于SqlDelight生成的接口适合AutoValue无缝接入的。AutoValue的作用的是,自己主动生成bean代码。AutoValue请点击我

使用须要导包

//基础AutoValue
apt 'com.google.auto.value:auto-value:1.4-rc3'
provided 'com.google.auto.value:auto-value:1.4-rc3' //AutoValue的扩展。为每一个AutoValue凝视对象创建一个简单的Gson TypeAdapterFactory。
//https://github.com/rharter/auto-value-gson
apt 'com.ryanharter.auto.value:auto-value-gson:0.4.6'
provided 'com.ryanharter.auto.value:auto-value-gson:0.4.6' //AutoValue的扩展。支持Android的Parcelable
apt 'com.ryanharter.auto.value:auto-value-parcel:0.2.5'
// 可选择TypeAdapter支持
compile 'com.ryanharter.auto.value:auto-value-parcel-adapter:0.2.5'

这时候User的bean为

@AutoValue
public abstract class User implements UserModel { public static final Factory<User> FACTORY = new Factory<>(new Creator<User>() {
@Override
public User create(long _id, @NonNull String name, long age) {
//AutoValue_User 须要先make一下module
return new AutoValue_User(_id,name,age);
}
}); public static final RowMapper<User> SELECT_ALL_MAPPER = FACTORY.select_by_nameMapper(); }

4. 使用

然后写一个Activity来測试看看(Sqlite相关知识请百度,点我看教程):

public class MainActivity extends AppCompatActivity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //创建获取名字为tp的数据库
SQLiteDatabase sqLiteDatabase = new StuDBHelp(this,"tp",null,1).getWritableDatabase();
//插入数据
sqLiteDatabase.insert("user",null,createContentValues(0,"天平",21));
sqLiteDatabase.insert("user",null,createContentValues(1,"逼辉",23)); Log.e("@@", "数据数量:: "+getAllUsers(sqLiteDatabase).size()); } public List<User> getAllUsers(SQLiteDatabase db) {
List<User> result = new ArrayList<>(); //try-with-resources写法,括号中面的资源须要继承AutoCloseable,作用是能够自己主动关闭对象
try (Cursor cursor = db.rawQuery(User.FACTORY.select_by_name().statement, new String[0])) { while (cursor.moveToNext()) {
result.add(User.SELECT_ALL_MAPPER.map(cursor));
} } return result;
} public ContentValues createContentValues(int id,String name,int age){
ContentValues contentValues = new ContentValues();
contentValues.put("_id",id);
contentValues.put("name",name);
contentValues.put("age",age);
return contentValues;
} class StuDBHelp extends SQLiteOpenHelper{ public StuDBHelp(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
} //第一次创建数据库的调用的方法
@Override
public void onCreate(SQLiteDatabase db) {
//db.execSQL(User.CREATE_TABLE);
//创建表
db.execSQL(User.CREATE_TABLE); } @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
} }

这时候你会看到输出:

数据数量:: 2

2.3 sq语句參数

.sq文件使用与SQLite全然同样的语法,包括SQLite绑定args(官方文档点我)。

假设语句包括绑定args。将在Factory上生成类型安全方法,该方法返回包括查询字符串。查询args和要查询的表的字段的SqlDelightStatement。

上面的样例中,我把sq文件中面的查询语句加入where条件,变成:

select_by_name: select * from user where name='天平';

然后又一次make一下module,然后改动查询的getAllUsers方法:

public List<User> getAllUsers(SQLiteDatabase db) {
List<User> result = new ArrayList<>(); //创建 SqlDelightStatement对象,里面有查询字符串和參数
SqlDelightStatement query = User.FACTORY.select_by_name("天平"); //try_with_resources写法。括号中面的资源须要继承AutoCloseable,作用是能够自己主动关闭对象
try (Cursor cursor = db.rawQuery(User.FACTORY.select_by_name("天平").statement, query.args)) { while (cursor.moveToNext()) {
result.add(User.SELECT_ALL_MAPPER.map(cursor));
} } return result;
}

此时能够看到输出:

数据数量:: 1

假设是数组就用IN:

select_by_names:
select * from user where name in ?;
public List<User> getAllUsers(SQLiteDatabase db) {
List<User> result = new ArrayList<>(); SqlDelightStatement query = User.FACTORY.select_by_name(new String[]{"天平","逼辉"}); try (Cursor cursor = db.rawQuery(query.statement, query.args)) {
while (cursor.moveToNext()) {
result.add(User.SELECT_ALL_MAPPER.map(cursor));
}
}
return result;
}

还能用运算符,比如查询user表的name字段是天开头的或结尾的:

-- 查询use表,百分号(%)代表零个、一个或多个数字或字符,||连接两个不同的字符串,得到一个新的字符串。?1 标识參数为同一个的意思
select_by_name: select * from user where
name like '%' || ? 1
or
name like ? 1 ||'%';
SqlDelightStatement query = User.FACTORY.select_by_name("天");
Cursor cursor = db.rawQuery(query.statement, query.args)

2.4 插入、更新、删除

运行多次的插入,更新和删除 都须要make一下module,SQLDelight会为为它们生成一个类型安全类。

比如在User.sq加入一句:

-- 更新 name为參数1 的年龄为參数2
update_age:
update user set age = ? where name = ?;

又一次make一下module会看到UserModel有一个Update_age类:

  final class Update_age extends SqlDelightCompiledStatement.Update {
public Update_age(SQLiteDatabase database) {
super("user", database.compileStatement(""
+ "update user set age = ? where name = ? "));
} public void bind(long age, @NonNull String name) {
program.bindLong(1, age);
program.bindString(2, name);
}
}

更新的时候(在上面的栗子的MainActivity的onCreate改动):

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //创建获取名字为tp的数据库
SQLiteDatabase sqLiteDatabase = new StuDBHelp(this,"tp",null,1).getWritableDatabase();
//插入数据
sqLiteDatabase.insert("user",null,createContentValues(0,"天平",21));
sqLiteDatabase.insert("user",null,createContentValues(1,"逼辉",23)); //创建Update_age对象
User.Update_age updateAge; updateAge = new User.Update_age(sqLiteDatabase);
//设置改动的值
updateAge.bind(66,"天平"); updateAge.bind(99,"逼辉"); //运行
updateAge.program.execute(); //运行。返回改动的行数,这种方法仅仅改动最后一个
//updateAge.program.executeUpdateDelete(); for(User user:getAllUsers(sqLiteDatabase)){
Log.e("@@", "user: "+user.toString());
} }

这时候会看到输出:

user: User{_id=0, name=天平, age=66}
user: User{_id=1, name=逼辉, age=99}

ps:注意: 假设是bind了多个,executeUpdateDelete仅仅能改动最后那个。 假设须要同一时候改动须要使用execute,如上面的代码

2.5 多个结果

选择返回多个结果列的话,要为查询生成的结果自己定义模型、映射程序和工厂方法。比如:

在User.sq底部加入语句:

-- 依据age分组,group_concat链接全部的同样age的名字(默认使用逗号链接)
names_for_age:
select age, group_concat(name)
from user
group by age;

在User bean里面加入一个类和静态常量:

@AutoValue
public abstract class User implements UserModel { //
public static final Factory<User> FACTORY = new Factory<>(new Creator<User>() {
@Override
public User create(long _id, @NonNull String name, long age) {
return new AutoValue_User(_id,name,age);
}
}); public static final RowMapper<User> SELECT_ALL_MAPPER = FACTORY.select_by_nameMapper(); @AutoValue
public abstract static class NamesForNumber implements Names_for_ageModel { public String[] names() { //调用接口里面的方法
return group_concat_name().split(",");
} } public static final RowMapper<NamesForNumber> NAMES_FOR_NUMBER_MAPPER =
FACTORY.names_for_ageMapper(new Names_for_ageCreator<NamesForNumber>() {
@Override
public NamesForNumber create(long age, @NonNull String group_concat_name) {
return new AutoValue_User_NamesForNumber(age,group_concat_name);
}
}); }

在MainActivity中使用看看:

public class MainActivity extends AppCompatActivity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //创建获取名字为tp的数据库
SQLiteDatabase sqLiteDatabase = new StuDBHelp(this,"tp",null,1).getWritableDatabase();
//插入数据
sqLiteDatabase.insert("user",null,createContentValues(0,"天平",21));
sqLiteDatabase.insert("user",null,createContentValues(1,"逼辉",23)); //保存数据到map
Map<Long,String[]> map = namesForNumber(sqLiteDatabase); //循环输出
for(Long age:map.keySet()){ String[] str = map.get(age);
String nameAll = "";
for(String s:str){
nameAll += s ;
} Log.e("@@", "数据: "+age+"-"+ nameAll); } } /**
* 从数据库查询,存放到map中,
* @parm db 数据库
*/
public Map<Long, String[]> namesForNumber(SQLiteDatabase db) { Map<Long, String[]> namesForNumberMap = new LinkedHashMap<>(); SqlDelightStatement sqlDelightStatement = User.FACTORY.names_for_age(); try (Cursor cursor = db.rawQuery(sqlDelightStatement.statement, new String[0])) {
while (cursor.moveToNext()) { User.NamesForNumber namesForNumber = NAMES_FOR_NUMBER_MAPPER.map(cursor); namesForNumberMap.put(namesForNumber.age(), namesForNumber.names());
}
}
return namesForNumberMap;
} public ContentValues createContentValues(int id,String name,int age){
ContentValues contentValues = new ContentValues();
contentValues.put("_id",id);
contentValues.put("name",name);
contentValues.put("age",age);
return contentValues;
} class StuDBHelp extends SQLiteOpenHelper{ public StuDBHelp(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
} //第一次创建数据库的调用的方法
@Override
public void onCreate(SQLiteDatabase db) {
//db.execSQL(User.CREATE_TABLE);
//创建表
db.execSQL(User.CREATE_TABLE); } @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
} }

然后能够看到输出:

数据: 66-天平
数据: 99-逼辉

2.6 类型转换

SQLDelight列定义与常规SQLite列定义同样,但支持转换类型(约束)。会在生成的接口中指定列的类型。比如:

CREATE TABLE some_types (
some_long INTEGER, -- 在数据库中存储为INTEGER,获取的时候为Long
some_double REAL, -- 在数据库中存储为REAL,获取的时候为Double
some_string TEXT, -- 在数据库中存储为TEXT,获取的时候为String
some_blob BLOB, -- 在数据库中存储为BLOB。获取的时候为byte[]
some_int INTEGER AS Integer, -- 在数据库中存储为INTEGER,获取的时候为Integer
some_short INTEGER AS Short, -- 在数据库中存储为INTEGER,获取的时候为Short
some_float REAL AS Float -- 在数据库中存储为REAL,获取的时候为Float
);

SQLDelight支持布尔列。能够将它们作为int存储在db中然后实现为int:

CREATE TABLE hockey_player (
injured INTEGER AS Boolean DEFAULT 0
)

2.7 其它类型保存

假设上面的基本类型不满足要求还能够自己定义类型,还能够指定java类型。

可是,须要提供一个ColumnAdapter,存储取出的时候进行转换。

自己定义类

又拿上面的User进行开刀(把上面的更新和分组查询删掉了)。加入一个表类型,加入一个插入数据的语句。


import java.util.Calendar; -- 注意这里要到导入包 create table user(
_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER NOT NULL,
-- 储存类型为INTEGER,取出来时候转换为Calendar
birth_date INTEGER AS Calendar NOT NULL
); -- 其它的语句通过标识符来引用。在生成的 Java 对象中会包括
-- 一个该标识符的常亮引用这个语句。 -- 查询use表,百分号(%)代表零个、一个或多个数字或字符,||连接两个不同的字符串。得到一个新的字符串。 select_by_name:
select * from user; -- 插入数据
insert_time:
insert into user (_id,name,age,birth_date) values (?,?,?,? );

User bean类里面加入一个ColumnAdapter,这时候User是这种

@AutoValue
public abstract class User implements UserModel { //须要自己新建一个列适配器
private static final ColumnAdapter<Calendar,Long> CALENDAR_ADAPTER = new ColumnAdapter<Calendar, Long>() {
@NonNull
@Override
public Calendar decode(Long databaseValue) {
//解码为Long,用于取出的时候转换为Calendar Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(databaseValue);
return calendar;
} @Override
public Long encode(@NonNull Calendar value) {
//编码为Long,用于保存到数据库
return value.getTimeInMillis();
}
}; //构造工厂,这里除了Creator參数,还加入了CALENDAR_ADAPTER 适配器參数
public static final Factory<User> FACTORY = new Factory<>(new Creator<User>() { @Override
public User create(long _id, @NonNull String name, long age, @NonNull Calendar birth_date) {
return new AutoValue_User(_id,name,age,birth_date);
}
},CALENDAR_ADAPTER); //行映射
public static final RowMapper<User> SELECT_ALL_MAPPER = FACTORY.select_by_nameMapper(); }

由于要又一次建立表,先把app卸载了。如今的MainActivity代码为:

public class MainActivity extends AppCompatActivity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //创建获取名字为tp的数据库
SQLiteDatabase sqLiteDatabase = new StuDBHelp(this,"tp",null,2).getWritableDatabase(); User.Insert_time delgiht= new User.Insert_time(sqLiteDatabase,User.FACTORY); delgiht.bind(0,"天平",21,Calendar.getInstance());
delgiht.program.executeInsert(); delgiht.bind(1,"傻逼",21,Calendar.getInstance());
delgiht.program.executeInsert(); delgiht.bind(2,"屌爆天",21,Calendar.getInstance());
delgiht.program.executeInsert(); delgiht.bind(3,"智障",21,Calendar.getInstance());
delgiht.program.executeInsert(); delgiht.program.clearBindings(); //清除绑定 for(User user:getAllUsers(sqLiteDatabase)){ Log.e("@@", "user: "+user._id() + user.name() + user.age() + user.birth_date().getTime());
} sqLiteDatabase.close(); //关闭数据库 } @RequiresApi(api = Build.VERSION_CODES.KITKAT)
public List<User> getAllUsers(SQLiteDatabase db) {
List<User> result = new ArrayList<>(); SqlDelightStatement query = User.FACTORY.select_by_name(); //try_with_resources写法,括号中面的资源须要继承AutoCloseable,作用是能够自己主动关闭对象
try (Cursor cursor = db.rawQuery(query.statement, query.args)) { while (cursor.moveToNext()) {
result.add(User.SELECT_ALL_MAPPER.map(cursor));
} } return result;
} public ContentValues createContentValues(int id,String name,int age){
ContentValues contentValues = new ContentValues();
contentValues.put("_id",id);
contentValues.put("name",name);
contentValues.put("age",age);
return contentValues;
} class StuDBHelp extends SQLiteOpenHelper{ public StuDBHelp(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
} //第一次创建数据库的调用的方法
@Override
public void onCreate(SQLiteDatabase db) {
//db.execSQL(User.CREATE_TABLE);
//创建表
db.execSQL(User.CREATE_TABLE); } @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
} }

这时候看到输出为:

0天平21Tue Mar 14 17:04:13 GMT+08:00 2017
1傻逼21Tue Mar 14 17:04:14 GMT+08:00 2017
2屌爆天21Tue Mar 14 17:04:14 GMT+08:00 2017
3智障21Tue Mar 14 17:04:14 GMT+08:00 2017

ps注意: 在插入的时候 executeInsert仅仅能插入bind的最后一行。execute也是,和select不一样。 还有sq里面的自己定义类型须要导包或者填写全路径

枚举

枚举能够转换为TEXT类型保存到数据库,sqlDelight有提供一个EnumColumnAdapter类:

继续拿User来开刀

首先在User bean加一个枚举:

    public enum Position {
CENTER, LEFT_WING, RIGHT_WING, DEFENSE, GOALIE
}

sq语句改为:

create table user(
_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER NOT NULL,
-- 储存类型为INTEGER。取出来时候转换为Calendar
birth_date INTEGER AS Calendar NOT NULL,
-- 全路径的方法
position TEXT as com.minstone.testsqldelight.User.Position NOT NULL
);
... -- 插入数据
insert_time:
insert into user (_id,name,age,birth_date,position) values (? ,?,?,? ,? );

User bean类加入一个EnumColumnAdapter适配器:

@AutoValue
public abstract class User implements UserModel { public enum Position {
CENTER, LEFT_WING, RIGHT_WING, DEFENSE, GOALIE
} //须要自己新建一个列适配器
private static final ColumnAdapter<Calendar,Long> CALENDAR_ADAPTER = new ColumnAdapter<Calendar, Long>() {
@NonNull
@Override
public Calendar decode(Long databaseValue) {
//解码为Long,用于取出的时候 Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(databaseValue);
return calendar;
} @Override
public Long encode(@NonNull Calendar value) {
//编码为Long。用于保存到数据库
return value.getTimeInMillis();
}
}; //枚举专用的适配器,在Factory加入參数
private static final ColumnAdapter<Position,String> POSITION_ADAPTER = EnumColumnAdapter.create(Position.class); //构造工厂
public static final Factory<User> FACTORY = new Factory<>(new Creator<User>() { @Override
public User create(long _id, @NonNull String name, long age, @NonNull Calendar birth_date, @NonNull Position position) {
return new AutoValue_User(_id,name,age,birth_date,position);
} },CALENDAR_ADAPTER,POSITION_ADAPTER); //行映射
public static final RowMapper<User> SELECT_ALL_MAPPER = FACTORY.select_by_nameMapper(); }

MainActivty如上面那样加入属性,输出log加user.position(),卸载app,运行看到结果:

0天平21Tue Mar 14 17:34:38 GMT+08:00 2017CENTER
1傻逼21Tue Mar 14 17:34:38 GMT+08:00 2017LEFT_WING
2屌爆天21Tue Mar 14 17:34:38 GMT+08:00 2017RIGHT_WING
3智障21Tue Mar 14 17:34:38 GMT+08:00 2017GOALIE

View

Sqlite中有视图View这个概念,sqlDelight也是支持的。

继续拿User开刀,加入两个语句:

.....

-- 查询创建视图
names_view:
CREATE VIEW names AS
SELECT substr(name, 0, 2) AS first_name,
substr(name, 2, length(name)) AS last_name,
_id
FROM user; -- 从视图中选择
select_names:
SELECT *
FROM names;

编辑之后,会在UserModle里面加入了NamesModel、NamesCreator、NamesMapper:

所以我们使用的时候和User几乎相同,在User bean类里面,引用映射器须要实现视图模型:


...... //实现NamesModel方法
@AutoValue
public static abstract class Names implements NamesModel { //留空就可以,AutoValue会生成相应的bean类方法
} //View的Names的行映射
public static final RowMapper<Names> NAMES_VIEW_MAPPER =
FACTORY.select_namesMapper(new UserModel.NamesCreator<User.Names>() {
@Override
public User.Names create(@NonNull final String first_name, @NonNull final String last_name, final long _id) {
return new AutoValue_User_Names(first_name,last_name,_id);
}
});

在MainActivity中来一发:

    protected void onCreate(Bundle savedInstanceState) {

        ......

        // 创建View
sqLiteDatabase.execSQL(User.NAMES_VIEW); // 查询View
for(User.Names names:getView(sqLiteDatabase)){ Log.e("@@", "user: " + names.first_name() + "-" +names.last_name()+ "-" + names._id());
} sqLiteDatabase.close(); //关闭数据库 } //获取view的list
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public List<User.Names> getView(SQLiteDatabase db) {
List<User.Names> result = new ArrayList<>(); //这是是查询View视图
SqlDelightStatement query = User.FACTORY.select_names(); //try_with_resources写法,括号中面的资源须要继承AutoCloseable,作用是能够自己主动关闭对象
try (Cursor cursor = db.rawQuery(query.statement, query.args)) { while (cursor.moveToNext()) {
//调用User里面的行映射
result.add(User.NAMES_VIEW_MAPPER.map(cursor));
} } return result;
} }

能够看到输出:

user: 天-平-0
傻-逼-1
屌-爆天-2
智-障-3

2.8 Join

链接多个表或者view视图。

接着上面来撸,在sq加入一个select_all_info:

select_all_info:
SELECT *
FROM user
JOIN names USING (_id);

在User的bean里面加入:

    @AutoValue
public static abstract class AllInfo implements Select_all_infoModel<User, Names> { } //注意select_all_infoMapper须要两个參数
public static final RowMapper<AllInfo> SELECT_ALL_INFO_MAPPER =
FACTORY.select_all_infoMapper(new Select_all_infoCreator<User, Names, AllInfo>() {
@Override
public AllInfo create(@NonNull User user, @NonNull Names names) {
return new AutoValue_User_AllInfo(user,names);
}
}, new NamesCreator<Names>() {
@Override
public Names create(@NonNull String first_name, @NonNull String last_name, long _id) {
return new AutoValue_User_Names(first_name, last_name, _id);
}
});

MainActivit里面使用:

    protected void onCreate(Bundle savedInstanceState) {

        ......

        // 创建View
sqLiteDatabase.execSQL(User.NAMES_VIEW); // allInfo
for(User.Names names:getView(sqLiteDatabase)){ Log.e("@@", "names: " + names.toString());
} // allInfo
for(User.AllInfo allInfo:getAllView(sqLiteDatabase)){ Log.e("@@", "allInfo: " + allInfo.toString());
} sqLiteDatabase.close(); //关闭数据库 } public List<User.AllInfo> getAllView(SQLiteDatabase db) {
List<User.AllInfo> result = new ArrayList<>(); //这是查询all info
SqlDelightStatement query = User.FACTORY.select_all_info(); //try_with_resources写法,括号中面的资源须要继承AutoCloseable,作用是能够自己主动关闭对象
try (Cursor cursor = db.rawQuery(query.statement, query.args)) { while (cursor.moveToNext()) { result.add(User.SELECT_ALL_INFO_MAPPER.map(cursor));
} } return result;
} }

Android SqlDelight具体解释和Demo样例的更多相关文章

  1. Android清理设备内存具体完整演示样例(二)

    版权声明: https://blog.csdn.net/lfdfhl/article/details/27672913 MainActivity例如以下: package cc.c; import j ...

  2. 10分钟理解Android数据库的创建与使用(附具体解释和演示样例代码)

    1.Android数据库简单介绍. Android系统的framework层集成了Sqlite3数据库.我们知道Sqlite3是一种轻量级的高效存储的数据库. Sqlite数据库具有以下长处: (1) ...

  3. Android平台调用Web Service:演示样例

    近期在学习Android,随着移动设备的流行,当软件走上商业化的道路,为了争夺市场,肯定须要支持Android的,所以開始接触了Android,只是仅仅了解皮毛就好,由于我们要做管理者嘛,懂点Andr ...

  4. RPM安装包-Spec文件參数具体解释与演示样例分析

    spec文件是整个RPM包建立过程的中心,它的作用就如同编译程序时的Makefile文件. 1.Spec文件參数 spec文件包括建立一个RPM包必需的信息,包括哪些文件是包的一部分以及它们安装在哪个 ...

  5. Android设计模式之中的一个个样例让你彻底明确装饰者模式(Decorator Pattern)

    导读 这篇文章中我不会使用概念性文字来说明装饰者模式.由于通常概念性的问题都非常抽象.非常难懂.使得读者非常难明确究竟为什么要使用这样的设计模式.我们设计模式的诞生,肯定是前辈们在设计程序的时候遇到了 ...

  6. Android清理设备内存具体完整演示样例(一)

    MainActivity例如以下: package come.on; import android.app.Activity; import android.content.Context; impo ...

  7. Android中特殊图形的生成样例

    import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; impor ...

  8. Android之——流量管理程序演示样例

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47680811 眼下.市面上有非常多管理手机流量的软件,能够让用户实时获取到自己手机 ...

  9. 构造Scala开发环境并创建ApiDemos演示样例项目

    从2011年開始写Android ApiDemos 以来.Android的版本号也更新了非常多,眼下的版本号已经是4.04. ApiDemos中的样例也添加了不少,有必要更新Android ApiDe ...

随机推荐

  1. BZOJ3277: 串(后缀自动机,Parent树,Dfs序)

    Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身). Input 第一行两个整数n, ...

  2. django 简单会议室预约(5)

    再来看看views.py的后半部分,对数据库的增删改查 #获取学院列表 def get_acad_list(): room_list = ConfeRoom.objects.all() #对数据库的操 ...

  3. Spring学习总结(5)——IOC注入方式总结

    一.构造注入 在类被实例化的时候,它的构造方法被调用并且只能调用一次.所以它被用于类的初始化操作.<constructor-arg>是<bean>标签的子标签.通过其<v ...

  4. mysql-5.7.19-winx64服务无法启动解决方案

    解压mysql压缩包时没有data文件夹,不要手动创建,在cmd下直接运行命令: mysqld –initialize-insecure,data文件夹会自动生成,注意单词千万不要拼错,不要写成–in ...

  5. iOS界面生命周期过程具体解释

    开发过Android的人都知道,每个Android界面就是一个Activity,而每个Activity都会有自己的生命周期, 有一系列方法会控制Activity的生命周期.如:onCreate(),o ...

  6. Android时间戳与字符串相互转换

    import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public cl ...

  7. IIS7性能优化

    http://www.03389.com/BLOG/user1/qq66565841/archives/2014/2014112143553.html IIS7性能优化 IIS7 优化-网站请求并发数 ...

  8. 网络博客 VC\图案像处理

    http://blog.csdn.net/lvwx369/article/category/1185452 http://blog.csdn.net/lyy289065406/article/deta ...

  9. VC 常见问题百问

    http://www.cnblogs.com/cy163/archive/2006/06/19/429796.html 经典Vc书 Charles Petzold 的<Programming W ...

  10. 【Codeforces Round #446 (Div. 2) B】Wrath

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 倒着来,维护一个最小的点就可以了. [代码] #include <bits/stdc++.h> using namesp ...