-
Notifications
You must be signed in to change notification settings - Fork 1.4k
C++ 增删查改
增删查改是数据库最常用的功能,因此 WCDB C++ 对其进行了特别的封装,使其通过一行代码即可完成操作。
插入操作有 insertObjects
、 insertOrReplaceObjects
、insertOrIgnoreObjects
三个接口。故名思义,第一个只是单纯的插入数据,当数据出现冲突时会失败。而后面两个在主键冲突等约束冲突出现时, insertOrReplaceObjects
会把新数据会覆盖旧数据,insertOrIgnoreObjects
则是会跳过插入冲突数据,但不产生错误。下面是 insertObjects
的函数原型, 另外两个函数与此相同,只是名字不同:
template<class ObjectType>
bool insertObjects(const ValueArray<ObjectType> &objs,
const UnsafeStringView &table,
const Fields &fields = Fields())
以已经完成模型绑定的类 Sample
为例:
// Sample.hpp
class Sample {
public:
Sample();//必须要有默认构造函数
Sample(int identifier, const std::string& content);//非必须实现的构造函数,只是为了演示方便
int identifier;
std::string content;
WCDB_CPP_ORM_DECLARATION(Sample)
};
// Sample.cpp
WCDB_CPP_ORM_IMPLEMENTATION_BEGIN(Sample)
WCDB_CPP_SYNTHESIZE(identifier)
WCDB_CPP_SYNTHESIZE(content)
WCDB_CPP_ORM_IMPLEMENTATION_END
bool ret = database.createTable<Sample>("sampleTable");
Sample object(1, "insert");
ret &= database.insertObjects<Sample>(object, "sampleTable");// 插入成功
ret &= database.insertObjects<Sample>(object, "sampleTable");// 插入失败,因为主键 identifier = 1 已经存在
object.content = "insertOrReplace";
ret &= database.insertOrReplaceObjects<Sample>(object, "sampleTable");// 插入成功,且 content 的内容会被替换为 "insertOrReplace"
object.content = "insertOrIgnore";
ret &= database.insertOrIgnoreObjects<Sample>(object, "sampleTable");// 插入成功,且 content 的内容不会被更改,还是"insertOrReplace"
关于自增插入,可参考模型绑定 - 自增属性一章。
需要插入的对象多时,还可以使用批量插入。当插入的对象数大于 1 时,WCDB 会自动开启事务,进行批量化地插入,以获得更好的性能。
Sample object2(2, "insert2");
Sample object3(3, "insert3");
// 两个对象要么一起插入成功,要么一起插入失败
ret &= database.insertObjects<Sample>({object2, object3}, "sampleTable");
除了插入整个对象,也可以只插入对象的部分属性:
Sample object4(4, "insert4");
// 部分插入,没有指定 WCDB_FIELD(Sample::content), "insert4"这个内容没有写入数据库,content字段的值为空
ret = database.insertObjects<Sample>(object4, "sampleTable", WCDB_FIELD(Sample::identifier));
这里的insertObjects
的第三个参数传入的实际是WCDB::Fields
对象,是一个描述对象字段组合的列表,在读写的场合用来指定读写对象的部分成员,我们会在语言集成查询中进一步介绍。
删除操作可以使用deleteObjects
接口,后面可按需传入 where
、orders
、limit
、offset
参数以删除部分数据,这个接口的原型是:
bool deleteObjects(const UnsafeStringView &table,
const Expression &where = Expression(),
const OrderingTerms &orders = OrderingTerms(),
const Expression &limit = Expression(),
const Expression &offset = Expression());
以下是删除接口的示例代码:
// 删除 sampleTable 中所有 identifier 大于 1 的行的数据
ret = database.deleteObjects("sampleTable", WCDB_FIELD(Sample::identifier) > 1);
// 删除 sampleTable 中 identifier 降序排列后的前 2 行数据
ret = database.deleteObjects("sampleTable",
WCDB::Expression(),//不需要传的参数可以用函数声明中的默认值跳过
WCDB_FIELD(Sample::identifier).asOrder(WCDB::Order::DESC),
2);
// 删除 sampleTable 中 content 非空的数据,按 identifier 降序排列后的前 3 行的后 2 行数据
ret = database.deleteObjects("sampleTable",
WCDB_FIELD(Sample::content).notNull(),
WCDB_FIELD(Sample::identifier).asOrder(WCDB::Order::DESC),
2,
3);
// 删除 sampleTable 中的所有数据
ret = database.deleteObjects("sampleTable");
这里的 where
、limit
和 offset
本质都是遵循 WCDB::Expression
的对象,可以是数字、字符串、字段或其他更多的组合。同样地,我们会在语言集成查询进一步介绍。
删除接口不会删除表本身,开发者需要调用
dropTable
接口删除表。
更新数据库的时候可以使用C++对象或结构体来更新数据库,也可以直接使用具体值来更新。使用C++对象或结构体的接口为: updateObject
,可以使用where
、orders
、limit
、offset
参数来指定更新范围,下面是函数原型:
template<class ObjectType>
bool updateObject(const ObjectType &obj,
const Fields &fields,
const UnsafeStringView &table,
const Expression &where = Expression(),
const OrderingTerms &orders = OrderingTerms(),
const Expression &limit = Expression(),
const Expression &offset = Expression());
下面是示例代码:
Sample object;
object.content = "update";
// 将 sampleTable 中所有 identifier 大于 1 且 content 字段不为空 的行的 content 字段更新为 "update"
ret = database.updateObject(object,
WCDB_FIELD(Sample::content),
"sampleTable",
WCDB_FIELD(Sample::identifier) > 1 && WCDB_FIELD(Sample::content).notNull());
// 将 sampleTable 中前三行的 content 字段更新为 "update"
ret = database.updateObject(object,
WCDB_FIELD(Sample::content),
"sampleTable",
WCDB::Expression(),//不需要传的参数可以用函数声明中的默认值跳过
3);
而使用值来更新数据库的接口分别是 updateRow
,可以使用where
、orders
、limit
、offset
参数来指定更新范围。row 是WCDB::Value
的数组,支持绑定字段的类型都可以转变为WCDB::Value
。下面是接口原型:
bool updateRow(const OneRowValue &row,
const Columns &columns,
const UnsafeStringView &table,
const Expression &where = Expression(),
const OrderingTerms &orders = OrderingTerms(),
const Expression &limit = Expression(),
const Expression &offset = Expression())
下面是使用示例:
// 将 sampleTable 中所有 identifier 大于 1 且 content 字段不为空的行的 content 字段更新为 "update"
ret = database.updateRow("update",
WCDB_FIELD(Sample::content),
"sampleTable",
WCDB_FIELD(Sample::identifier) > 1 && WCDB_FIELD(Sample::content).notNull());
// 将 sampleTable 中 identifier 为 1 行的 identifier 字段更新为2,content 字段更新为 "update2"
ret = database.updateRow({2, "update"},
Sample::allFields(),
"sampleTable",
WCDB_FIELD(Sample::identifier) == 1);
这里用到的Sample::allFields()
等价于{WCDB_FIELD(Sample::identifier), WCDB_FIELD(Sample::content)}
,allFields
是获取ORM类所有DB配置的字段的便捷方法。
查找接口接口较多,但大部分都是为了简化操作而提供的便捷接口,和更新接口类似,实现上主要分为对象查找和值查找两大类接口。
getFirstObject
和 getAllObjects
都是对象查找的接口,他们直接返回已进行模型绑定的对象或结构体,它们都可以使用where
、orders
、limit
、offset
参数来指定查询范围。
而 getFirstObject
等价于 limit
为 1 时的 getAllObjects
接口。不同的是,它直接返回 Object
对象,而不是一个数组,使用上更便捷。 getFirstObject
的原型如下,getAllObjects
的原型与此相同:
template<class ObjectType>
Optional<ObjectType> getFirstObject(const UnsafeStringView &table,
const Expression &where = Expression(),
const OrderingTerms &orders = OrderingTerms(),
const Expression &offset = Expression())
以下是对象查找操作的示例代码:
// 返回 sampleTable 中的所有数据
WCDB::OptionalValueArray<Sample> allObjects = database.getAllObjects<Sample>("sampleTable");
// 返回 sampleTable 中 identifier 小于 5 或 大于 10 的行的数据
WCDB::OptionalValueArray<Sample> objects = database.getAllObjects<Sample>("sampleTable", WCDB_FIELD(Sample::identifier) < 5 || WCDB_FIELD(Sample::identifier) > 10);
// 返回 sampleTable 中 identifier 最大的行的数据
WCDB::Optional<Sample> object = database.getFirstObject<Sample>("sampleTable",
//不需要传的参数可以用函数声明中的默认值跳过
WCDB::Expression(),
WCDB_FIELD(Sample::identifier).asOrder(WCDB::Order::DESC));
查询接口的返回数据都是
WCDB::Optional
类型,WCDB::Optional
的succeed
函数返回true时,才表示结果有效,可以使用value
函数获取到具体值。如果succeed
函数返回false,则表示查询失败了,没有结果返回。
与 "insert"、"update" 类似,对象查找操作也支持指定字段,这种接口有getFirstObjectWithFields
和 getAllObjectsWithFields
两个,区别还是前者查单个对象,后者查一组对象,这两个接口都可以使用where
、orders
、limit
、offset
参数来指定查找范围。 getFirstObjectWithFields
的原型如下,getAllObjectsWithFields
的原型与此相同:
template<class ObjectType>
Optional<ObjectType>
getFirstObjectWithFields(const UnsafeStringView &table,
const ResultFields &resultFields,
const Expression &where = Expression(),
const OrderingTerms &orders = OrderingTerms(),
const Expression &offset = Expression())
下面是使用示例:
// 返回 sampleTable 中的所有identifier字段,返回结果中的content内容为空
WCDB::OptionalValueArray<Sample> allObjects = database.getAllObjectsWithFields<Sample>("sampleTable", WCDB_FIELD(Sample::identifier));
值查询有下面四类接口,这些接口都可以使用where
、orders
、limit
、offset
参数来指定查找范围:
selectValue
selectOneColumn
selectOneRow
selectAllRow
试考虑,表中的数据可以想象为一个矩阵的存在,假设其数据如下:
identifier | content |
---|---|
1 | "sample1" |
2 | "sample1" |
3 | "sample2" |
4 | "sample2" |
5 | "sample2" |
在不考虑 where
、orders
、limit
和 offset
参数的情况下:
-
selectAllRow
接口获取整个矩阵的所有内容,即返回值为二维数组。 -
selectOneRow
接口获取某一横行的数据,即返回值为一维数组。 -
selectOneColumn
接口获取某一纵列的数据,即返回值为一维数组。 -
selectValue
接口获取矩阵中某一个格的内容。
以下是值查询操作的示例代码:
// 获取所有内容
WCDB::OptionalMultiRows allRows = database.selectAllRow(Sample::allFields(), "sampleTable");
printf("%lld", allRows.value()[2][0].intValue()); // 输出 3
// 获取第二行
WCDB::OptionalOneRow secondRow = database.selectOneRow(Sample::allFields(),
"sampleTable",
//不需要传的参数可以用函数声明中的默认值跳过
WCDB::Expression(),
1);
printf("%lld", secondRow.value()[0].intValue()); // 输出 3
// 获取第三行 content 列的值
WCDB::OptionalOneColumn contentColumn = database.selectOneColumn(WCDB_FIELD(Sample::content), "sampleTable");
printf("%s", contentColumn.value()[2].textValue().data()); // 输出 sample2
// 获取第二列第二行的值
WCDB::OptionalValue value = database.selectValue(WCDB_FIELD(Sample::content),
"sampleTable",
//不需要传的参数可以用函数声明中的默认值跳过
WCDB::Expression(),
WCDB::OrderingTerms(),
1);
printf("%s", value.value().textValue().data()); // 输出 sample1
// 获取 identifier 的最大值
WCDB::OptionalValue maxId = database.selectValue(WCDB_FIELD(Sample::identifier).max(), "sampleTable");
printf("%lld", maxId.value().intValue()); // 输出 5
这里 WCDB_FIELD(Sample::identifier).max()
是可以转换 WCDB::ResultColumn
的对象,用于查找 identifier
列的最大值。我们会在语言集成查询中进一步介绍。
- 欢迎使用 WCDB
- 基础教程
- 进阶教程
- 欢迎使用 WCDB
- 基础教程
- 进阶教程
- 欢迎使用 WCDB
- 基础教程
- 进阶教程
- 欢迎使用 WCDB
- 基础教程
- 进阶教程