示例
注
仅适用于 Windows 系统上的 .NET Framework 4.x 和 .NET 8(原 .NET Core)。
以下代码片段演示了一个基本的嵌入式 SmartESQL C# 应用程序实现:
public static void Main(String[] args)
{
Database db;
Database.Device[] devs;
Database.Parameters parameters = new Database.Parameters();
bool disk = false;
bool shared = false;
bool use_dptr = false;
Database.Mode mode = 0;
String binPath;
// get config parameters from the command line
foreach (String s in args)
{
switch (s)
{
case "disk":
disk = true;
mode |= Database.Mode.DiskSupport;
break;
case "shm":
shared = true;
mode |= Database.Mode.SharedMemorySupport;
break;
case "mvcc":
mode |= Database.Mode.MVCCTransactionManager;
break;
case "dptr":
use_dptr = true;
break;
case "debug":
mode |= Database.Mode.DebugSupport;
break;
default:
binPath = s;
break;
}
}
binPath = FindLibrary(use_dptr);
int hint = use_dptr ? 0x20000000 : 0;
parameters.MemPageSize = PAGE_SIZE; // memory page size
parameters.Classes = new Type[] { typeof(MyTable) };
parameters.MaxConnections = 10;
if (disk) // on-disk configuration
{
if (System.IO.File.Exists("opendb.dbs"))
System.IO.File.Delete("opendb.dbs");
if (System.IO.File.Exists("opendb.log"))
System.IO.File.Delete("opendb.log");
parameters.DiskPageSize = DISK_PAGE_SIZE; // disk page size
parameters.DiskClassesByDefault = true; // mark @Persistent classes as
// on-disk classes by default
// declare memory devices
devs = new Database.Device[4];
if (shared)
{
devs[0] = new Database.SharedMemoryDevice(Database.Device.Kind.Data,
"opendb-db", new IntPtr(hint),DATABASE_SIZE);
devs[1] = new Database.SharedMemoryDevice(Database.Device.Kind.DiskCache,
"opendb-cache", new IntPtr(hint),DISK_CACHE_SIZE);
}
else
{
devs[0] = new Database.PrivateMemoryDevice(Database.Device.Kind.Data,
DATABASE_SIZE);
devs[1] = new atabase.PrivateMemoryDevice(Database.Device.Kind.DiskCache,
DISK_CACHE_SIZE);
}
devs[2] = new Database.FileDevice(Database.Device.Kind.Data, "opendb.dbs");
devs[3] = new Database.FileDevice(Database.Device.Kind.TransactionLog, "opendb.log");
}
else // in-memory configuration
{
devs = new Database.Device[1];
if (shared)
{
devs[0] = new Database.SharedMemoryDevice(Database.Device.Kind.Data,
"opendb-db", new IntPtr(hint), DATABASE_SIZE);
}
else
{
devs[0] = new Database.PrivateMemoryDevice(Database.Device.Kind.Data,
DATABASE_SIZE);
}
}
// create Database object
db = new Database(mode, binPath);
db.Open("sqldb", parameters, devs); // open database.
一旦打开数据库,就必须创建一个连接来访问它。应用程序可以通过 Database 类创建连接,例如:
Database db = new Database(Database.Mode.DebugSupport,“../../target/bin.so");
int maxAttempts = 10;
SqlLocalConnection conLocal = db.ConnectSql();
SqlRemoteConnection conRemote = db.ConnectRemoteSql(host, port, maxAttempts);
或者可以通过调用 SqlLocalConnection 或 SqlRemoteConnection 构造函数来实例化连接。请注意,对于远程连接的一个限制是,当前在单个连接中无法同时执行多个查询。因此,例如,如下这样的操作将无法实现:
SqlResultSet rs1 = conRemote.executeQuery("select * from Class1");
SqlResultSet rs2 = conRemote.executeQuery("select * from Class2");
Iterator<Class1> i1 = rs1.iterator();
Iterator<Class2> i2 = rs2.iterator();
while (i1.hasNext() && i2.hasNext())
{
...
}
然后使用 ExecuteQuery() 方法执行 SQL 查询,该方法执行 SQL 选择语句并返回一个 SqlResultSet,或者使用 ExecuteStatement() 方法执行 SQL 插入、更新或删除语句,并返回受影响的行数。例如:
SqlLocalConnection con = db.ConnectSql();
con.StartTransaction(Database.TransactionType.ReadWrite);
con.ExecuteStatement("insert into MyTable (pk,value) values (?,?)", 2012,
"Good bye");
con.ExecuteStatement("insert into MyTable (pk,value) values (?,?)", 2013,
"Hello");
con.CommitTransaction();
con.StartTransaction(Database.TransactionType.ReadOnly);
using (SqlResultSet result = con.ExecuteQuery("select pk,value from MyTable”
“ where pk>=?", 2013))
{
foreach (string column in result.ColumnNames)
{
Console.Write(column + ", ");
}
Console.WriteLine();
foreach (SqlTuple tuple in result)
{
Console.WriteLine(tuple[0] + ", " + tuple["value"]);
}
}
con.CommitTransaction();
con.Disconnect();
db.Close();
Console.ReadLine();
}
}
请注意,数据库事务必须通过 con.StartTransaction() 显式启动,并通过 con.CommitTransaction() 或 con.RollbackTransaction() 关闭。连接必须通过 con.Disconnect() 关闭,数据库必须通过 db.Close() 关闭。另外,ExecuteQuery() 和 ExecuteStatement() 这两个方法都允许将参数替换到语句中,以替换标记为 ? 或 %x 的占位符,其中 x 指定参数类型,可以是以下类型之一:
%b = bool
%i = signed<4>
%u = unsigned<4>
%l = signed<8>
%t = datetime
%s = string
%w = nstring
在大多数情况下,可以使用传统的 ODBC/JDBC 占位符“?”。如果您想将字符串作为 Unicode(宽字符)字符串(%w)而不是多字节字符字符串(%s)传递,则需要特定的参数类型说明符。例如:
con.ExecuteQuery("select * from Employee where department=? and salary > ?", "HR", 50000);
ExecuteQuery() 方法返回一个实现了 IEnumerable<SqlTuple> 接口的 SqlResultSet 对象。建议使用 using 语句来使用此 SqlResultSet,例如:
using ( SqlResultSet result = con.ExecuteQuery(
"select pk,value from MyTable where pk>=?", 2013) )
{
foreach (string column in result.ColumnNames)
{
Console.Write(column + ", ");
}
Console.WriteLine();
foreach (SqlTuple tuple in result)
{
Console.WriteLine(tuple[0] + ", " + tuple["value"]);
}
}
using 子句会在其作用域结束时调用 Dispose() 方法,从而释放查询资源。还可以获取结果列的数目和列名列表。SqlResultSet.GetEnumerator() 方法返回一个 SqlCursor 实例,该实例实现了 IEnumerator<SqlTuple> 接口,并提供对所选元组的一次性迭代。(请注意,无法重置迭代器以重新开始遍历。)SqlTuple 类表示列值的集合。它提供了获取列数的方法(不过最好从 SqlResultSet 而不是从元组获取此数字)以及提取特定列值的方法。 可以通过索引(从 0 开始)或名称(如上例所示)访问列。
返回值的类型为:
- bool
- long
- double
- decimal
- String
- byte[]
- DateTime
通过索引访问元组的值是推荐的做法,因为使用列名需要进行哈希查找。可以使用一次 SqlResultSet.GetColumnNo(string columnName)
方法通过列名获取列的索引;然后使用返回的索引来获取元组的值。