ORM Lite is a C++ Object Relation Mapping (ORM) for SQLite3, written in Modern C++ style.
- Easy to Use
- Light Weight
- Compile-time Overhead
- Strong Typed
- Fluent Interface
Before we start, Include src into your Project:
ORMLite.h
sqlite3.h
andsqlite3.c
#include "ORMLite.h"
using namespace BOT_ORM;
using namespace BOT_ORM::Expression;
struct UserModel
{
int user_id;
std::string user_name;
double credit_count;
Nullable<int> age;
Nullable<double> salary;
Nullable<std::string> title;
// Inject ORM-Lite into this Class :-)
ORMAP ("UserModel", user_id, user_name, credit_count,
age, salary, title);
};
Nullable<T>
helps us construct Nullable
Value in C++,
which is described in the Document 😁
In this Sample, ORMAP ("UserModel", ...)
do that:
Class UserModel
will be mapped intoTABLE UserModel
;- NOT
Nullable
members will be mapped asNOT NULL
; int, double, std::string
will be mapped intoINT, REAL, TEXT
respectively;- The first entry
id
will be set as the Primary Key of the Table;
// Open a Connection with *test.db*
ORMapper mapper ("test.db");
// Create a table for "UserModel"
mapper.CreateTbl (UserModel {});
// Drop the table "UserModel"
mapper.DropTbl (UserModel {});
user_id | user_name | credit_count | age | salary | title |
---|---|---|---|---|---|
0 | John | 0.2 | 21 | null |
null |
1 | Jack | 0.4 | null |
3.14 | null |
2 | Jess | 0.6 | null |
null |
Dr. |
... | ... | ... | ... | ... | ... |
std::vector<UserModel> initObjs =
{
{ 0, "John", 0.2, 21, nullptr, nullptr },
{ 1, "Jack", 0.4, nullptr, 3.14, nullptr },
{ 2, "Jess", 0.6, nullptr, nullptr, std::string ("Dr.") }
};
// Insert Values into the table
for (const auto &obj : initObjs)
mapper.Insert (obj);
initObjs[1].salary = nullptr;
initObjs[1].title = "St.";
// Update Entity by Primary Key (WHERE UserModel.id = 1)
mapper.Update (initObjs[1]);
// Delete Entity by Primary Key (WHERE UserModel.id = 2)
mapper.Delete (initObjs[2]);
// Transactional Statements
try
{
mapper.Transaction ([&] ()
{
mapper.Delete (initObjs[0]); // OK
mapper.Insert (UserModel { 1, "Joke", 0 }); // Failed
});
}
catch (const std::exception &ex)
{
// If any statement Failed, throw an exception
// "SQL error: UNIQUE constraint failed: UserModel.id"
// Remarks:
// mapper.Delete (initObjs[0]); will not applied :-)
}
// Select All to List
auto result1 = mapper.Query (UserModel {}).ToList ();
// result1 = [{ 0, 0.2, "John", 21, null, null },
// { 1, 0.4, "Jack", null, null, "St." }]
std::vector<UserModel> dataToSeed;
for (int i = 50; i < 100; i++)
dataToSeed.emplace_back (
UserModel { i, "July_" + std::to_string (i), i * 0.2 });
// Insert by Batch Insert
mapper.Transaction ([&] () {
mapper.InsertRange (dataToSeed);
});
for (size_t i = 0; i < 20; i++)
{
dataToSeed[i + 30].age = 30 + (int) i / 2;
dataToSeed[i + 20].title = "Mr. " + std::to_string (i);
}
// Update by Batch Update
mapper.Transaction ([&] () {
mapper.UpdateRange (dataToSeed);
});
// Define a Query Helper Object and its Field Extractor
UserModel helper;
FieldExtractor field { helper };
// Select by Query
auto result2 = mapper.Query (UserModel {})
.Where (
field (helper.user_name) & std::string ("July%") &&
(field (helper.age) >= 32 &&
field (helper.title) != nullptr)
)
.OrderByDescending (field (helper.age))
.OrderBy (field (helper.user_id))
.Take (3)
.Skip (1)
.ToVector ();
// Remarks:
// sql = SELECT * FROM UserModel
// WHERE (user_name LIKE 'July%' AND
// (age>=32 AND title IS NOT NULL))
// ORDER BY age DESC
// ORDER BY id
// LIMIT 3 OFFSET 1
// result2 = [{ 89, 17.8, "July_89", 34, null, "Mr. 19" },
// { 86, 17.2, "July_86", 33, null, "Mr. 16" },
// { 87, 17.4, "July_87", 33, null, "Mr. 17" }]
// Calculate Aggregate Function by Query
auto avg = mapper.Query (UserModel {})
.Where (field (helper.user_name) & std::string ("July%"))
.Select (Avg (field (helper.credit_count)));
// Remarks:
// sql = SELECT AVG (credit_count) FROM UserModel
// WHERE (user_name LIKE 'July%')
// avg = 14.9
auto count = mapper.Query (UserModel {})
.Where (field (helper.user_name) | std::string ("July%"))
.Select (Count ());
// Remarks:
// sql = SELECT COUNT (*) FROM UserModel
// WHERE (user_name NOT LIKE 'July%')
// count = 2
// Update by Condition
mapper.Update (
UserModel {},
(field (helper.age) = 10) &&
(field (helper.credit_count) = 1.0),
field (helper.user_name) == std::string ("July"));
// Remarks:
// sql = UPDATE UserModel SET age=10,credit_count=1.0
// WHERE (user_name='July')
// Delete by Condition
mapper.Delete (UserModel {},
field (helper.user_id) >= 90);
// Remarks:
// sql = DELETE FROM UserModel WHERE (id>=90)
// Define more Query Helper Objects and their Field Extractor
UserModel user;
SellerModel seller;
OrderModel order;
field = FieldExtractor { user, seller, order };
// Insert Values into the table
// mapper.Insert (..., false) means Insert without Primary Key
for (size_t i = 0; i < 50; i++)
mapper.Insert (
OrderModel { 0,
(int) i / 2 + 50,
(int) i / 4 + 50,
"Item " + std::to_string (i),
i * 0.5 }, false);
// Join Tables for Query
auto joinedQuery = mapper.Query (UserModel {})
.Join (OrderModel {},
field (user.user_id) ==
field (order.user_id))
.LeftJoin (SellerModel {},
field (seller.seller_id) ==
field (order.seller_id))
.Where (field (user.user_id) >= 65);
// Get Result to List
// Results are Nullable-Tuples
auto result3 = joinedQuery.ToList ();
// Remarks:
// sql = SELECT * FROM UserModel
// JOIN OrderModel
// ON UserModel.user_id=OrderModel.user_id
// LEFT JOIN SellerModel
// ON SellerModel.seller_id=OrderModel.seller_id
// WHERE (UserModel.user_id>=65)
// result3 = [(65, "July_65", 13, null, null, null,
// 31, 65, 57, "Item 30", 15,
// null, null, null),
// (65, "July_65", 13, null, null, null,
// 32, 65, 57, "Item 31", 15.5,
// null, null, null),
// ... ]
// Group & Having ~
// Results are Nullable-Tuples
auto result4 = joinedQuery
.Select (field (order.user_id),
field (user.user_name),
Avg (field (order.fee)))
.GroupBy (field (user.user_name))
.Having (Sum (field (order.fee)) >= 40.5)
.Skip (3)
.ToList ();
// Remarks:
// sql = SELECT OrderModel.user_id,
// UserModel.user_name,
// AVG (OrderModel.fee)
// FROM UserModel
// JOIN OrderModel
// ON UserModel.user_id=OrderModel.user_id
// LEFT JOIN SellerModel
// ON SellerModel.seller_id=OrderModel.seller_id
// WHERE (UserModel.user_id>=65)
// GROUP BY UserModel.user_name
// HAVING SUM (OrderModel.fee)>=40.5
// LIMIT ~0 OFFSET 3
// result4 = [(73, "July_73", 23.25),
// (74, "July_74", 24.25)]
// Compound Select
// Results are Nullable-Tuples
auto result5 = mapper.Query (OrderModel {})
.Select (field (order.product_name), field (order.user_id))
.Where (field (order.user_id) == 50)
.Union (
joinedQuery
.Select (field (user.user_name), field (order.order_id))
)
.Take (4)
.ToList ();
// sql = SELECT OrderModel.product_name,
// OrderModel.user_id
// FROM OrderModel
// WHERE (OrderModel.user_id==50)
// UNION
// SELECT UserModel.user_name,
// OrderModel.order_id
// FROM UserModel
// JOIN OrderModel
// ON UserModel.user_id=OrderModel.user_id
// LEFT JOIN SellerModel
// ON SellerModel.seller_id=OrderModel.seller_id
// WHERE (UserModel.user_id>=65)
// LIMIT 4;
// result5 = [("Item 0", 50),
// ("Item 1", 50),
// ("July_65", 31),
// ("July_65", 32)]
- Blob / DateTime Types
- Subquery
- Constraints on Creating Table
Posts in Chinese only: