diff --git a/Apewer.Source/Apewer.Source.csproj b/Apewer.Source/Apewer.Source.csproj
index f6b622a..1c15c33 100644
--- a/Apewer.Source/Apewer.Source.csproj
+++ b/Apewer.Source/Apewer.Source.csproj
@@ -27,6 +27,18 @@
+
+
+
+
+
+
+
+ $(DefineConstants);MYSQL_6_10;
+
+
+
+
diff --git a/Apewer.Source/Internals/TextHelper.cs b/Apewer.Source/Internals/TextHelper.cs
new file mode 100644
index 0000000..61247c0
--- /dev/null
+++ b/Apewer.Source/Internals/TextHelper.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Apewer.Internals
+{
+
+ internal static class TextHelper
+ {
+
+ public static StringPairs ParseConnectionString(string connectionString)
+ {
+ var sp = new StringPairs();
+ if (string.IsNullOrEmpty(connectionString)) return sp;
+
+ var split = connectionString.Split(";");
+ foreach (var item in split)
+ {
+ var equal = item.IndexOf("=");
+ if (equal < 0) continue;
+ var left = item.Substring(0, equal).ToTrim();
+ var right = item.Substring(equal + 1).ToTrim();
+ if (left.IsEmpty() || right.IsEmpty()) continue;
+ sp.Add(left, right);
+ }
+ return sp;
+ }
+
+ }
+
+}
diff --git a/Apewer.Source/Source/Access.cs b/Apewer.Source/Source/Access.cs
index 6cee814..0863201 100644
--- a/Apewer.Source/Source/Access.cs
+++ b/Apewer.Source/Source/Access.cs
@@ -24,59 +24,34 @@ namespace Apewer.Source
#if NETFRAMEWORK
- public partial class Access : IDatabaseBase, IDatabaseQuery, IDatabaseExecute, IDisposable
+ public partial class Access : IDbClientBase, IDbClientAdo, IDisposable
{
- /// 创建 Access 类的新实例。
- public static Access Jet4() => new Access(AccessHelper.JetOleDB4);
-
- /// 创建 Access 类的新实例。
- public static Access Ace12() => new Access(AccessHelper.AceOleDB12);
-
- #region 属性、构造函数和 Dispose。
-
- private OleDbConnection _connection = null;
-
- internal string Provider { get; set; }
+ #region 连接
- /// 构造函数。
- internal Access(string provider)
- {
- Provider = provider;
- Timeout = new Timeout();
- }
-
- /// 释放资源。
- public void Dispose() => Close();
-
- #endregion
-
- #region 日志。
+ string _connstr = null;
+ OleDbConnection _connection = null;
+ Timeout _timeout = null;
/// 获取或设置日志记录。
public Logger Logger { get; set; }
- private void LogError(string action, Exception ex, string addtion)
+ /// 获取或设置超时。
+ public Timeout Timeout { get => _timeout; }
+
+ /// 构造函数。
+ public Access(string connectrionString, Timeout timeout)
{
- var logger = Logger;
- if (logger != null) logger.Error(this, "Access", action, ex.GetType().FullName, ex.Message, addtion);
+ _connstr = connectrionString;
+ _timeout = timeout ?? Timeout.Default;
}
#endregion
- #region 连接。
+ #region 连接
- /// 获取或设置数据库文件的路径。
- public string Path { get; set; }
-
- /// Microsoft Access System Database。
- public string Josd { get; set; }
-
- /// 获取或设置用于连接数据库的密码。
- public string Pass { get; set; }
-
- /// 获取或设置超时。
- public Timeout Timeout { get; set; }
+ /// 获取当前的 OldDbConnection 对象。
+ public IDbConnection Connection { get => _connection; }
/// 数据库是否已经连接。
public bool Online
@@ -95,11 +70,10 @@ namespace Apewer.Source
/// 是否已连接。
public bool Connect()
{
- var cs = GenerateConnectionString();
if (_connection == null)
{
_connection = new OleDbConnection();
- _connection.ConnectionString = cs;
+ _connection.ConnectionString = _connstr;
}
else
{
@@ -110,9 +84,9 @@ namespace Apewer.Source
_connection.Open();
if (_connection.State == ConnectionState.Open) return true;
}
- catch (Exception argException)
+ catch (Exception ex)
{
- LogError("Connect", argException, cs);
+ Logger.Error(nameof(Access), "Connect", ex, _connstr);
Close();
}
return false;
@@ -123,35 +97,91 @@ namespace Apewer.Source
{
if (_connection != null)
{
+ if (_transaction != null)
+ {
+ if (_autocommit) Commit();
+ else Rollback();
+ }
_connection.Close();
_connection.Dispose();
_connection = null;
}
}
- /// 获取或设置连接字符串。
- private string GenerateConnectionString()
- {
- if (!File.Exists(Path)) return null;
+ /// 释放资源。
+ public void Dispose() => Close();
- var sb = new StringBuilder();
+ #endregion
- sb.Append("provider=", Provider, "; ");
+ #region Transaction
- if (!string.IsNullOrEmpty(Path)) sb.Append("data source=", Path, "; ");
+ private IDbTransaction _transaction = null;
+ private bool _autocommit = false;
- if (string.IsNullOrEmpty(Pass)) sb.Append("persist security info=false; ");
- else sb.Append("jet oledb:database password=\"", Pass, "\"; ");
+ /// 启动事务。
+ public string Begin(bool commit = true) => Begin(commit, null);
- // Microsoft Access Workgroup Information
- if (!string.IsNullOrEmpty(Josd)) sb.Append("jet oledb:system database=", Josd, "; ");
+ /// 启动事务。
+ public string Begin(bool commit, Class isolation)
+ {
+ if (!Connect()) return "未连接。";
+ if (_transaction != null) return "存在已启动的事务,无法再次启动。";
+ try
+ {
+ _transaction = isolation ? _connection.BeginTransaction(isolation.Value) : _connection.BeginTransaction();
+ _autocommit = commit;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(nameof(Access), "Begin", ex.Message());
+ return ex.Message();
+ }
+ }
- return sb.ToString();
+ /// 提交事务。
+ public string Commit()
+ {
+ if (_transaction == null) return "事务不存在。";
+ try
+ {
+ _transaction.Commit();
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ Logger.Error(nameof(Access), "Commit", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ /// 从挂起状态回滚事务。
+ public string Rollback()
+ {
+ if (_transaction == null) return "事务不存在。";
+ try
+ {
+ _transaction.Rollback();
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ Logger.Error(nameof(Access), "Rollback", ex.Message);
+ return ex.Message();
+ }
}
#endregion
- #region 查询和执行。
+ #region 查询和执行
/// 使用 SQL 语句进行查询。
public IQuery Query(string sql) => Query(sql, null);
@@ -161,43 +191,40 @@ namespace Apewer.Source
{
if (sql.IsBlank()) return Example.InvalidQueryStatement;
- const string table = "queryresult";
-
var connected = Connect();
if (!connected) return Example.InvalidQueryConnection;
- var query = new Query();
try
{
- var command = new OleDbCommand();
- command.Connection = _connection;
- command.CommandTimeout = Timeout.Query;
- command.CommandText = sql;
- if (parameters != null)
+ using (var command = new OleDbCommand())
{
- foreach (var p in parameters)
+ command.Connection = _connection;
+ command.CommandTimeout = Timeout.Query;
+ command.CommandText = sql;
+ if (parameters != null)
{
- if (p != null) command.Parameters.Add(p);
+ foreach (var p in parameters)
+ {
+ if (p != null) command.Parameters.Add(p);
+ }
}
- }
- using (var ds = new DataSet())
- {
- using (var da = new OleDbDataAdapter(sql, _connection))
+ using (var ds = new DataSet())
{
- da.Fill(ds, table);
- query.Table = ds.Tables[table];
+ using (var da = new OleDbDataAdapter(sql, _connection))
+ {
+ const string name = "result";
+ da.Fill(ds, name);
+ var table = ds.Tables[name];
+ return new Query(table);
+ }
}
}
- command.Dispose();
- query.Success = true;
}
catch (Exception exception)
{
- LogError("Query", exception, sql);
- query.Success = false;
- query.Exception = exception;
+ Logger.Error(nameof(Access), "Query", exception, sql);
+ return new Query(exception);
}
- return query;
}
/// 执行 SQL 语句。
@@ -211,40 +238,35 @@ namespace Apewer.Source
var connected = Connect();
if (!connected) return Example.InvalidExecuteConnection;
- var execute = new Execute();
- using (var transaction = _connection.BeginTransaction())
+ var inTransaction = _transaction != null;
+ if (!inTransaction) Begin();
+ try
{
- try
+ using (var command = new OleDbCommand())
{
- using (var command = new OleDbCommand())
+ command.Connection = _connection;
+ command.Transaction = (OleDbTransaction)_transaction;
+ command.CommandTimeout = Timeout.Execute;
+ command.CommandText = sql;
+ if (parameters != null)
{
- command.Connection = _connection;
- command.Transaction = transaction;
- command.CommandTimeout = Timeout.Execute;
- command.CommandText = sql;
- if (parameters != null)
+ foreach (var parameter in parameters)
{
- foreach (var parameter in parameters)
- {
- if (parameter == null) continue;
- command.Parameters.Add(parameter);
- }
+ if (parameter == null) continue;
+ command.Parameters.Add(parameter);
}
- execute.Rows += command.ExecuteNonQuery();
- transaction.Commit();
}
- execute.Success = true;
- }
- catch (Exception exception)
- {
- LogError("Execute", exception, sql);
- try { transaction.Rollback(); } catch { }
- execute.Success = false;
- execute.Exception = exception;
+ var rows = command.ExecuteNonQuery();
+ if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
+ return new Execute(true, rows);
}
}
-
- return execute;
+ catch (Exception exception)
+ {
+ Logger.Error(nameof(Access), "Execute", exception, sql);
+ if (!inTransaction) Rollback();
+ return new Execute(exception);
+ }
}
#endregion
@@ -280,20 +302,41 @@ namespace Apewer.Source
#endregion
+ #region protected
+
+ /// 获取或设置连接字符串。
+ internal protected static string GenerateCS(string provider, string path, string pass, string jo)
+ {
+ if (!File.Exists(path)) return null;
+
+ var sb = new StringBuilder();
+
+ sb.Append("provider=", provider, "; ");
+
+ if (!string.IsNullOrEmpty(path)) sb.Append("data source=", path, "; ");
+
+ if (string.IsNullOrEmpty(pass)) sb.Append("persist security info=false; ");
+ else sb.Append("jet oledb:database password=\"", pass, "\"; ");
+
+ // Microsoft Access Workgroup Information
+ if (!string.IsNullOrEmpty(jo)) sb.Append("jet oledb:system database=", jo, "; ");
+
+ return sb.ToString();
+ }
+
+ #endregion
+
}
/// 使用 Microsoft.Jet.OLEDB.4.0 访问 Access 97 - 2003 数据库文件。
public class AccessJet4 : Access
{
- /// 创建 Access 类的新实例。
- public AccessJet4() : base(AccessHelper.JetOleDB4) { }
+ const string JetOleDB4 = "microsoft.jet.oledb.4.0";
/// 创建 Access 类的新实例。
- public AccessJet4(string path) : base(AccessHelper.JetOleDB4)
- {
- Path = path;
- }
+ public AccessJet4(string path, string pass = null, string jo = null, Timeout timeout = null)
+ : base(GenerateCS(JetOleDB4, path, pass, jo), timeout) { }
}
@@ -301,14 +344,11 @@ namespace Apewer.Source
public class AccessAce12 : Access
{
- /// 创建 Access 类的新实例。
- public AccessAce12() : base(AccessHelper.AceOleDB12) { }
+ const string AceOleDB12 = "microsoft.ace.oledb.12.0";
/// 创建 Access 类的新实例。
- public AccessAce12(string path) : base(AccessHelper.AceOleDB12)
- {
- Path = path;
- }
+ public AccessAce12(string path, string pass = null, string jo = null, Timeout timeout = null)
+ : base(GenerateCS(AceOleDB12, path, pass, jo), timeout) { }
}
diff --git a/Apewer.Source/Source/MySql.cs b/Apewer.Source/Source/MySql.cs
index ee1a3ff..35469e5 100644
--- a/Apewer.Source/Source/MySql.cs
+++ b/Apewer.Source/Source/MySql.cs
@@ -1,75 +1,61 @@
#if MYSQL_6_9 || MYSQL_6_10
-/* 2021.09.23 */
+/* 2021.10.14 */
using Externals.MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Data;
+using System.Net;
using System.Text;
+using System.Transactions;
namespace Apewer.Source
{
///
- public class MySql : IDatabase
+ public class MySql : IDbClient
{
- #region fields & properties
+ #region 基础
- private const string EmptyString = TextUtility.Empty;
+ private Timeout _timeout = null;
+ private string _connectionstring = null;
- private MySqlConnection _connection = null;
- private Timeout _timeout = new Timeout();
- private string _address = EmptyString;
- private string _store = EmptyString;
- private string _user = "root";
- private string _pass = EmptyString;
-
- ///
- public string Address { get { return _address; } set { _address = TextUtility.AntiInject(value); } }
-
- ///
- public string Store { get { return _store; } set { _store = TextUtility.AntiInject(value); } }
-
- ///
- public string User { get { return _user; } set { _user = TextUtility.AntiInject(value); } }
-
- ///
- public string Pass { get { return _pass; } set { _pass = TextUtility.AntiInject(value); } }
+ /// 获取或设置日志记录。
+ public Logger Logger { get; set; }
- ///
- public Timeout Timeout { get { return _timeout; } set { _timeout = value; } }
+ /// 超时设定。
+ public Timeout Timeout { get => _timeout; }
- ///
- public bool Online
+ /// 创建实例。
+ public MySql(string connnectionString, Timeout timeout = default)
{
- get
- {
- if (_connection == null) return false;
- return _connection.State == ConnectionState.Open;
- }
+ _connectionstring = connnectionString;
+ _timeout = timeout ?? Timeout.Default;
}
- ///
- public MySql() { }
+ /// 获取当前的 MySqlConnection 对象。
+ public IDbConnection Connection { get => _connection; }
- ///
- public MySql(string address, string store, string user, string pass = null)
+ /// 构建连接字符串以创建实例。
+ public MySql(string address, string store, string user, string pass, Timeout timeout = null)
{
- Address = address;
- Store = store;
- User = user;
- Pass = pass;
+ _timeout = timeout ?? Timeout.Default;
+
+ var a = TextUtility.AntiInject(address);
+ var s = TextUtility.AntiInject(store);
+ var u = TextUtility.AntiInject(user);
+ var p = TextUtility.AntiInject(pass);
+ var cs = $"server={a}; database={s}; uid={u}; pwd={p}; ";
+ _connectionstring = cs;
+ _storename = new Class(s);
}
#endregion
#region 日志。
- /// 获取或设置日志记录。
- public Logger Logger { get; set; }
-
private void LogError(string action, Exception ex, string addtion)
{
var logger = Logger;
@@ -78,12 +64,15 @@ namespace Apewer.Source
#endregion
- #region methods
+ #region Connection
- private string CombineString()
- {
- return TextUtility.Merge("server=", _address, "; database=", _store, "; uid=", _user, "; pwd=", _pass, ";");
- }
+ private MySqlConnection _connection = null;
+
+ ///
+ public bool Online { get => _connection == null ? false : (_connection.State == ConnectionState.Open); }
+
+ /// 连接字符串。
+ public string ConnectionString { get => _connectionstring; }
///
public bool Connect()
@@ -91,7 +80,7 @@ namespace Apewer.Source
if (_connection == null)
{
_connection = new MySqlConnection();
- _connection.ConnectionString = CombineString();
+ _connection.ConnectionString = _connectionstring;
}
else
{
@@ -120,6 +109,11 @@ namespace Apewer.Source
{
if (_connection != null)
{
+ if (_transaction != null)
+ {
+ if (_autocommit) Commit();
+ else Rollback();
+ }
_connection.Close();
_connection.Dispose();
_connection = null;
@@ -129,48 +123,117 @@ namespace Apewer.Source
///
public void Dispose() { Close(); }
+ #endregion
+
+ #region Transaction
+
+ private IDbTransaction _transaction = null;
+ private bool _autocommit = false;
+
+ /// 启动事务。
+ public string Begin(bool commit = true) => Begin(commit, null);
+
+ /// 启动事务。
+ public string Begin(bool commit, Class isolation)
+ {
+ if (!Connect()) return "未连接。";
+ if (_transaction != null) return "存在已启动的事务,无法再次启动。";
+ try
+ {
+ _transaction = isolation ? _connection.BeginTransaction(isolation.Value) : _connection.BeginTransaction();
+ _autocommit = commit;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(nameof(MySql), "Commit", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ /// 提交事务。
+ public string Commit()
+ {
+ if (_transaction == null) return "事务不存在。";
+ try
+ {
+ _transaction.Commit();
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ Logger.Error(nameof(MySql), "Commit", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ /// 从挂起状态回滚事务。
+ public string Rollback()
+ {
+ if (_transaction == null) return "事务不存在。";
+ try
+ {
+ _transaction.Rollback();
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ Logger.Error(nameof(MySql), "Rollback", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ #endregion
+
+ #region SQL
+
///
public IQuery Query(string sql, IEnumerable parameters)
{
if (sql.IsBlank()) return Example.InvalidQueryStatement;
- const string table = "queryresult";
-
var connected = Connect();
if (!connected) return Example.InvalidQueryConnection;
- var query = new Query();
try
{
- var command = new MySqlCommand();
- command.Connection = _connection;
- command.CommandTimeout = _timeout.Query;
- command.CommandText = sql;
- if (parameters != null)
+ using (var command = new MySqlCommand())
{
- foreach (var p in parameters)
+ command.Connection = _connection;
+ command.CommandTimeout = _timeout.Query;
+ command.CommandText = sql;
+ if (parameters != null)
{
- if (p != null) command.Parameters.Add(p);
+ foreach (var p in parameters)
+ {
+ if (p != null) command.Parameters.Add(p);
+ }
}
- }
- using (var ds = new DataSet())
- {
- using (var da = new MySqlDataAdapter(sql, _connection))
+ using (var ds = new DataSet())
{
- da.Fill(ds, table);
- query.Table = ds.Tables[table];
+ using (var da = new MySqlDataAdapter(sql, _connection))
+ {
+ const string name = "result";
+ da.Fill(ds, name);
+ var table = ds.Tables[name];
+ return new Query(table);
+ }
}
}
- command.Dispose();
- query.Success = true;
}
catch (Exception exception)
{
- LogError("Query", exception, sql);
- query.Success = false;
- query.Exception = exception;
+ Logger.Error(nameof(MySql), "Query", exception, sql);
+ return new Query(exception);
}
- return query;
}
///
@@ -181,37 +244,35 @@ namespace Apewer.Source
var connected = Connect();
if (!connected) return Example.InvalidExecuteConnection;
- var transaction = _connection.BeginTransaction();
- var execute = new Execute();
+ var inTransaction = _transaction != null;
+ if (!inTransaction) Begin();
try
{
- var command = new MySqlCommand();
- command.Connection = _connection;
- command.Transaction = transaction;
- command.CommandTimeout = _timeout.Execute;
- command.CommandText = sql;
- if (parameters != null)
+ using (var command = new MySqlCommand())
{
- foreach (var parameter in parameters)
+ command.Connection = _connection;
+ command.Transaction = (MySqlTransaction)_transaction;
+ command.CommandTimeout = _timeout.Execute;
+ command.CommandText = sql;
+ if (parameters != null)
{
- if (parameter == null) continue;
- command.Parameters.Add(parameter);
+ foreach (var parameter in parameters)
+ {
+ if (parameter == null) continue;
+ command.Parameters.Add(parameter);
+ }
}
+ var rows = command.ExecuteNonQuery();
+ if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
+ return new Execute(true, rows);
}
- execute.Rows += command.ExecuteNonQuery();
- transaction.Commit();
- command.Dispose();
- execute.Success = true;
}
catch (Exception exception)
{
- LogError("Execute", exception, sql);
- try { transaction.Rollback(); } catch { }
- execute.Success = false;
- execute.Exception = exception;
+ Logger.Error(nameof(MySql), "Execute", exception, sql);
+ if (!inTransaction) Rollback();
+ return new Execute(exception);
}
- try { transaction.Dispose(); } catch { }
- return execute;
}
///
@@ -241,29 +302,38 @@ namespace Apewer.Source
#region ORM
- private List FirstColumn(string sql)
+ private Class _storename = null;
+
+ private string StoreName()
+ {
+ if (_storename) return _storename.Value;
+ _storename = new Class(Internals.TextHelper.ParseConnectionString(_connectionstring).GetValue("database"));
+ return _storename.Value ?? "";
+ }
+
+ private string[] FirstColumn(string sql)
{
using (var query = Query(sql) as Query) return query.ReadColumn();
}
///
- public List TableNames()
+ public string[] TableNames()
{
- var sql = TextUtility.Merge("select table_name from information_schema.tables where table_schema='", _store, "' and table_type='base table';");
+ var sql = TextUtility.Merge("select table_name from information_schema.tables where table_schema='", StoreName(), "' and table_type='base table';");
return FirstColumn(sql);
}
///
- public List ViewNames()
+ public string[] ViewNames()
{
- var sql = TextUtility.Merge("select table_name from information_schema.tables where table_schema='", _store, "' and table_type='view';");
+ var sql = TextUtility.Merge("select table_name from information_schema.tables where table_schema='", StoreName(), "' and table_type='view';");
return FirstColumn(sql);
}
///
- public List ColumnNames(string table)
+ public string[] ColumnNames(string table)
{
- var sql = TextUtility.Merge("select column_name from information_schema.columns where table_schema='", _store, "' and table_name='", TextUtility.AntiInject(table), "';");
+ var sql = TextUtility.Merge("select column_name from information_schema.columns where table_schema='", StoreName(), "' and table_name='", TextUtility.AntiInject(table), "';");
return FirstColumn(sql);
}
@@ -273,9 +343,9 @@ namespace Apewer.Source
// 检查现存表。
var exists = false;
var tables = TableNames();
- if (tables.Count > 0)
+ if (tables.Length > 0)
{
- var lower = structure.Table.ToLower();
+ var lower = structure.Name.ToLower();
foreach (var table in tables)
{
if (TextUtility.IsBlank(table)) continue;
@@ -289,10 +359,10 @@ namespace Apewer.Source
if (exists)
{
- var columns = ColumnNames(structure.Table);
- if (columns.Count > 0)
+ var columns = ColumnNames(structure.Name);
+ if (columns.Length > 0)
{
- var lower = new List(columns.Count);
+ var lower = new List(columns.Length);
var added = 0;
foreach (var column in columns)
{
@@ -301,10 +371,10 @@ namespace Apewer.Source
added++;
}
lower.Capacity = added;
- columns = lower;
+ columns = lower.ToArray();
}
var sqlsb = new StringBuilder();
- foreach (var column in structure.Columns.Values)
+ foreach (var column in structure.Columns)
{
// 检查 Independent 特性。
if (structure.Independent && column.Independent) continue;
@@ -317,7 +387,7 @@ namespace Apewer.Source
if (type.IsEmpty()) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
// alter table `_record` add column `_index` bigint;
- sqlsb.Append("alter table `", structure.Table, "` add column ", type, "; ");
+ sqlsb.Append("alter table `", structure.Name, "` add column ", type, "; ");
}
var sql = sqlsb.ToString();
return sql;
@@ -326,14 +396,11 @@ namespace Apewer.Source
{
// create table _record (`_index` bigint, `_key` varchar(255), `_text` longtext) engine=innodb default charset=utf8mb4
- var columns = new List(structure.Columns.Count);
+ var columns = new List(structure.Columns.Length);
var columnsAdded = 0;
var primarykey = null as string;
- foreach (var kvp in structure.Columns)
+ foreach (var column in structure.Columns)
{
- var property = kvp.Key;
- var column = kvp.Value;
-
// 检查 Independent 特性。
if (structure.Independent && column.Independent) continue;
@@ -344,10 +411,10 @@ namespace Apewer.Source
columnsAdded++;
// 主键。
- if (property == "Key") primarykey = column.Field;
+ if (column.Property.Name == "Key") primarykey = column.Field;
}
columns.Capacity = columnsAdded;
- var table = structure.Table;
+ var table = structure.Name;
var joined = string.Join(", ", columns);
// 设置主键。
@@ -370,22 +437,21 @@ namespace Apewer.Source
{
if (model == null)
{
- sql = "";
+ sql = null;
return "指定的类型无效。";
}
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(model); }
- catch (Exception exception)
+ var structure = TableStructure.Parse(model);
+ if (structure == null)
{
- sql = "";
- return exception.Message;
+ sql = null;
+ return "无法解析记录模型。";
}
// 连接数据库。
if (!Connect())
{
- sql = "";
+ sql = null;
return "连接数据库失败。";
}
@@ -393,7 +459,7 @@ namespace Apewer.Source
if (sql.NotEmpty())
{
var execute = Execute(sql);
- if (!execute.Success) return execute.Error;
+ if (!execute.Success) return execute.Message;
}
return null;
}
@@ -407,62 +473,56 @@ namespace Apewer.Source
///
public string Initialize(Record model) => (model == null) ? "参数无效。" : Initialize(model.GetType());
- /// 插入记录。成功时候返回空字符串,发生异常时返回异常信息。
+ /// 插入记录。返回错误信息。
public string Insert(IRecord record)
{
if (record == null) return "参数无效。";
record.FixProperties();
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(record); }
- catch (Exception exception) { return exception.Message; }
+ var structure = TableStructure.Parse(record.GetType());
+ if (structure == null) return "无法解析记录模型。";
- var parameters = structure.CreateDataParameters(record, CreateDataParameter);
- var sql = GenerateInsertStatement(structure.Table, parameters);
+ var parameters = structure.CreateParameters(record, CreateDataParameter);
+ var sql = GenerateInsertStatement(structure.Name, parameters);
var execute = Execute(sql, parameters);
if (execute.Success) return TextUtility.Empty;
- return execute.Error;
+ return execute.Message;
}
- ///
- /// 更新记录,实体中的 Created 和 Key 属性不被更新。成功时返回空字符串,发生异常时返回异常信息。
- /// 无法更新拥有 Independent 特性的模型。
- ///
+ /// 更新记录,实体中的 Key 属性不被更新。返回错误信息。
+ /// 无法更新带有 Independent 特性的模型(缺少 Key 属性)。
public string Update(IRecord record)
{
if (record == null) return "参数无效。";
record.FixProperties();
record.SetUpdated();
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(record); }
- catch (Exception exception) { return exception.Message; }
-
- // 检查 Independent 特性。
- if (structure.Independent) return "无法更新拥有 Independent 特性的模型。";
+ var structure = TableStructure.Parse(record.GetType());
+ if (structure == null) return "无法解析记录模型。";
+ if (structure.Independent) return "无法更新带有 Independent 特性的模型。";
- var parameters = structure.CreateDataParameters(record, CreateDataParameter, "_created", "_key");
+ var parameters = structure.CreateParameters(record, CreateDataParameter, "_key");
var sql = GenerateUpdateStatement(structure, record.Key, parameters);
var execute = Execute(sql, parameters);
if (execute.Success) return TextUtility.Empty;
- return execute.Error;
+ return execute.Message;
}
///
- public Result> Query(Type model, string sql) => OrmHelper.Query(this, model, sql);
+ public Result Query(Type model, string sql) => OrmHelper.Query(this, model, sql);
///
- public Result> Query(string sql) where T : class, IRecord, new() => OrmHelper.Query(this, sql);
+ public Result Query(string sql) where T : class, IRecord, new() => OrmHelper.Query(this, sql);
/// 获取所有记录。Flag 为 0 时将忽略 Flag 条件。
- public Result> Query(Type model, long flag = 0) => OrmHelper.Query(this, model, (tn) =>
+ public Result Query(Type model, long flag = 0) => OrmHelper.Query(this, model, (tn) =>
{
if (flag == 0) return $"select * from `{tn}`; ";
return $"select * from `{tn}` where `_flag`={flag}; ";
});
/// 获取所有记录。Flag 为 0 时将忽略 Flag 条件。
- public Result> Query(long flag = 0) where T : class, IRecord, new() => OrmHelper.Query(this, (tn) =>
+ public Result Query(long flag = 0) where T : class, IRecord, new() => OrmHelper.Query(this, (tn) =>
{
if (flag == 0) return $"select * from `{tn}`; ";
return $"select * from `{tn}` where `_flag`={flag}; ";
@@ -472,22 +532,20 @@ namespace Apewer.Source
/// 填充的记录模型。
/// 要跳过的记录数,可用最小值为 0。
/// 要获取的记录数,可用最小值为 1。
- ///
- public Result> Query(Type model, int skip, int count)
+ public Result Query(Type model, int skip, int count)
{
- if (skip < 0) return new Result>(new ArgumentOutOfRangeException(nameof(skip)));
- if (count < 1) return new Result>(new ArgumentOutOfRangeException(nameof(count)));
+ if (skip < 0) return new Result("参数 skip 超出了范围。");
+ if (count < 1) return new Result("参数 count 超出了范围。");
return OrmHelper.Query(this, model, (tn) => $"select * from `{tn}` limit {skip}, {count}; ");
}
/// 获取记录。
/// 要跳过的记录数,可用最小值为 0。
/// 要获取的记录数,可用最小值为 1。
- ///
- public Result> Query(int skip, int count) where T : class, IRecord, new()
+ public Result Query(int skip, int count) where T : class, IRecord, new()
{
- if (skip < 0) return new Result>(new ArgumentOutOfRangeException(nameof(skip)));
- if (count < 1) return new Result>(new ArgumentOutOfRangeException(nameof(count)));
+ if (skip < 0) return new Result("参数 skip 超出了范围。");
+ if (count < 1) return new Result("参数 count 超出了范围。");
return OrmHelper.Query(this, (tn) => $"select * from `{tn}` limit {skip}, {count}; ");
}
@@ -506,14 +564,14 @@ namespace Apewer.Source
});
/// >获取指定类型的主键,按 Flag 属性筛选。
- public Result> Keys(Type model, long flag = 0) => OrmHelper.Keys(this, model, (tn) =>
+ public Result Keys(Type model, long flag = 0) => OrmHelper.Keys(this, model, (tn) =>
{
if (flag == 0) return $"select `_key` from `{tn}`;";
return $"select `_key` from `{tn}` where `_flag`={flag};";
});
/// >获取指定类型的主键,按 Flag 属性筛选。
- public Result> Keys(long flag = 0) where T : class, IRecord, new() => Keys(typeof(T), flag);
+ public Result Keys(long flag = 0) where T : class, IRecord, new() => Keys(typeof(T), flag);
/// 对表添加列,返回错误信息。
/// 记录类型。
@@ -521,12 +579,14 @@ namespace Apewer.Source
/// 字段类型。
/// 字段长度,仅对 VarChar 和 NVarChar 类型有效。
///
- public string AddColumn(string column, ColumnType type, int length = 0) where T : Record
+ public string AddColumn(string column, ColumnType type, int length = 0) where T : class, IRecord
{
var columnName = SafeColumn(column);
if (columnName.IsEmpty()) return "列名无效。";
- var tableName = TableStructure.ParseTable(typeof(T)).Name;
+ var ta = TableAttribute.Parse(typeof(T));
+ if (ta == null) return "无法解析记录模型。";
+ var tableName = ta.Name;
var columeType = "";
switch (type)
@@ -547,9 +607,9 @@ namespace Apewer.Source
case ColumnType.NVarChar:
columeType = $"varchar({length})";
break;
- case ColumnType.VarChar255:
- case ColumnType.NVarChar255:
- columeType = "varchar(255)";
+ case ColumnType.VarChar191:
+ case ColumnType.NVarChar191:
+ columeType = "varchar(191)";
break;
case ColumnType.VarCharMax:
case ColumnType.NVarCharMax:
@@ -563,7 +623,7 @@ namespace Apewer.Source
var sql = $"alter table `{tableName}` add {columnName} {columeType}; ";
var execute = Execute(sql) as Execute;
- var error = execute.Error;
+ var error = execute.Message;
return error;
}
@@ -650,10 +710,10 @@ namespace Apewer.Source
dbtype = MySqlDbType.DateTime;
break;
case ColumnType.VarChar:
- case ColumnType.VarChar255:
+ case ColumnType.VarChar191:
case ColumnType.VarCharMax:
case ColumnType.NVarChar:
- case ColumnType.NVarChar255:
+ case ColumnType.NVarChar191:
case ColumnType.NVarCharMax:
dbtype = MySqlDbType.VarChar;
break;
@@ -671,9 +731,9 @@ namespace Apewer.Source
case ColumnType.NVarChar:
size = NumberUtility.Restrict(size, 0, 65535);
break;
- case ColumnType.VarChar255:
- case ColumnType.NVarChar255:
- size = NumberUtility.Restrict(size, 0, 255);
+ case ColumnType.VarChar191:
+ case ColumnType.NVarChar191:
+ size = NumberUtility.Restrict(size, 0, 191);
break;
default:
size = 0;
@@ -725,8 +785,8 @@ namespace Apewer.Source
case ColumnType.VarChar:
type = TextUtility.Merge("varchar(", Math.Max(65535, length).ToString(), ")");
break;
- case ColumnType.VarChar255:
- type = TextUtility.Merge("varchar(255)");
+ case ColumnType.VarChar191:
+ type = TextUtility.Merge("varchar(191)");
break;
case ColumnType.VarCharMax:
type = TextUtility.Merge("varchar(max)");
@@ -737,8 +797,8 @@ namespace Apewer.Source
case ColumnType.NVarChar:
type = TextUtility.Merge("varchar(", Math.Min(65535, length).ToString(), ")");
break;
- case ColumnType.NVarChar255:
- type = TextUtility.Merge("varchar(255)");
+ case ColumnType.NVarChar191:
+ type = TextUtility.Merge("varchar(191)");
break;
case ColumnType.NVarCharMax:
type = TextUtility.Merge("varchar(65535)");
@@ -844,7 +904,7 @@ namespace Apewer.Source
{
var result = TextUtility.Empty;
- var table = TextUtility.AntiInject(structure.Table, 255);
+ var table = TextUtility.AntiInject(structure.Name, 255);
if (TextUtility.IsEmpty(table)) return result;
var safekey = TextUtility.AntiInject(key, 255);
@@ -885,7 +945,7 @@ namespace Apewer.Source
if (structure == null) throw new ArgumentNullException("structure");
if (key == null) throw new ArgumentNullException("key");
- var table = TextUtility.AntiInject(structure.Table, 255);
+ var table = TextUtility.AntiInject(structure.Name, 255);
if (TextUtility.IsBlank(table)) throw new ArgumentException("表名无效。", "structure");
var safekey = TextUtility.AntiInject(key, 255);
diff --git a/Apewer.Source/Source/SqlServer.cs b/Apewer.Source/Source/SqlClient.cs
similarity index 63%
rename from Apewer.Source/Source/SqlServer.cs
rename to Apewer.Source/Source/SqlClient.cs
index 0e5eb94..6948af9 100644
--- a/Apewer.Source/Source/SqlServer.cs
+++ b/Apewer.Source/Source/SqlClient.cs
@@ -1,6 +1,4 @@
-#if NETFRAMEWORK
-
-/* 2021.09.23 */
+/* 2021.10.14 */
using Apewer;
using Apewer.Source;
@@ -8,88 +6,74 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
-using System.Data.Sql;
using System.Data.SqlClient;
+using System.Net;
using System.Text;
+#if NETFRAMEWORK
+using System.Data.Sql;
+#else
+#endif
+
namespace Apewer.Source
{
- /// 用于快速连接 Microsoft SQL Server 数据库的辅助。
+ ///
[Serializable]
- public class SqlClinet : IDatabase
+ public class SqlClient : IDbClient
{
- #region 变量定义。
-
- private SqlConnection _db = null;
+ #region 变量、构造函数
- private Timeout _timeout;
+ private Timeout _timeout = null;
private string _connectionstring = "";
- private string _address = "";
- private string _store = "";
- private string _user = "";
- private string _pass = "";
- #endregion
+ /// 获取或设置日志记录。
+ public Logger Logger { get; set; }
- #region 构造函数。
-
- /// 创建空参数的数据库连接实例。
- public SqlClinet()
- {
- _timeout = Timeout.Default;
- }
+ /// 超时设定。
+ public Timeout Timeout { get => _timeout; }
/// 使用连接字符串创建数据库连接实例。
- public SqlClinet(string connectionString)
+ public SqlClient(string connectionString, Timeout timeout = null)
{
- _timeout = Timeout.Default;
+ _timeout = timeout ?? Timeout.Default;
_connectionstring = connectionString ?? "";
}
/// 使用连接凭据创建数据库连接实例。
- /// 服务器地址。
- /// 数据库名称。
- public SqlClinet(string address, string store)
- {
- _timeout = Timeout.Default;
- _address = address ?? "";
- _store = store ?? "";
- UpdateConnectString();
- }
+ public SqlClient(string address, string store, string user, string pass, Timeout timeout = null)
+ {
+ if (timeout == null) timeout = Timeout.Default;
- /// 使用连接凭据创建数据库连接实例。
- /// 服务器地址。
- /// 数据库名称。
- /// 用户名。
- /// 密码。
- public SqlClinet(string address, string store, string user, string pass)
- {
- _timeout = Timeout.Default;
- _address = address ?? "";
- _store = store ?? "";
- _user = user ?? "";
- _pass = pass ?? "";
- UpdateConnectString();
+ var a = TextUtility.AntiInject(address);
+ var s = TextUtility.AntiInject(store);
+ var u = TextUtility.AntiInject(user);
+ var p = TextUtility.AntiInject(pass);
+ var cs = $"data source = {a}; initial catalog = {s}; ";
+ if (string.IsNullOrEmpty(u)) cs += "integrated security = sspi; ";
+ else
+ {
+ cs += $"user id = {u}; ";
+ if (!string.IsNullOrEmpty(p)) cs += $"password = {p}; ";
+ }
+ cs += $"connection timeout = {timeout.Connect}; ";
+
+ _timeout = timeout ?? Timeout.Default;
+ _connectionstring = cs;
}
#endregion
- #region 日志。
-
- /// 获取或设置日志记录。
- public Logger Logger { get; set; }
+ #region Ado - Connection
- private void LogError(string action, Exception ex, string addtion)
- {
- var logger = Logger;
- if (logger != null) logger.Error(this, "SQL Server", action, ex.GetType().FullName, ex.Message, addtion);
- }
+ private SqlConnection _db = null;
- #endregion
+ /// 连接字符串。
+ public string ConnectionString { get => _connectionstring; }
- #region 实现接口。
+ /// 获取当前的 SqlConnection 对象。
+ public IDbConnection Connection { get => _db; }
/// 数据库是否已经连接。
public bool Online
@@ -107,7 +91,7 @@ namespace Apewer.Source
if (_db == null)
{
_db = new SqlConnection();
- _db.ConnectionString = ConnectionString;
+ _db.ConnectionString = _connectionstring;
}
else
{
@@ -124,7 +108,7 @@ namespace Apewer.Source
}
catch (Exception ex)
{
- LogError("Connection", ex, _db.ConnectionString);
+ Logger.Error(nameof(SqlClient), "Connection", ex, _db.ConnectionString);
Close();
return false;
}
@@ -135,6 +119,11 @@ namespace Apewer.Source
{
if (_db != null)
{
+ if (_transaction != null)
+ {
+ if (_autocommit) Commit();
+ else Rollback();
+ }
_db.Close();
_db.Dispose();
_db = null;
@@ -142,16 +131,80 @@ namespace Apewer.Source
}
/// 关闭连接,释放对象所占用的系统资源,并清除连接信息。
- public void Dispose()
- {
- Close();
- _connectionstring = "";
- _address = "";
- _store = "";
- _user = "";
- _pass = "";
+ public void Dispose() => Close();
+
+ #endregion
+
+ #region Ado - Transaction
+
+ private IDbTransaction _transaction = null;
+ private bool _autocommit = false;
+
+ /// 启动事务。
+ public string Begin(bool commit = true) => Begin(commit, null);
+
+ /// 启动事务。
+ public string Begin(bool commit, Class isolation)
+ {
+ if (!Connect()) return "未连接。";
+ if (_transaction != null) return "存在已启动的事务,无法再次启动。";
+ try
+ {
+ _transaction = isolation ? _db.BeginTransaction(isolation.Value) : _db.BeginTransaction();
+ _autocommit = commit;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(nameof(SqlClient), "Begin", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ /// 提交事务。
+ public string Commit()
+ {
+ if (_transaction == null) return "事务不存在。";
+ try
+ {
+ _transaction.Commit();
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ Logger.Error(nameof(SqlClient), "Commit", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ /// 从挂起状态回滚事务。
+ public string Rollback()
+ {
+ if (_transaction == null) return "事务不存在。";
+ try
+ {
+ _transaction.Rollback();
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ Logger.Error(nameof(SqlClient), "Rollback", ex.Message);
+ return ex.Message();
+ }
}
+ #endregion
+
+ #region Ado - SQL
+
/// 查询。
public IQuery Query(string sql) => Query(sql, null);
@@ -159,44 +212,40 @@ namespace Apewer.Source
public IQuery Query(string sql, IEnumerable parameters)
{
if (TextUtility.IsBlank(sql)) return Example.InvalidQueryStatement;
-
- const string tablename = "queryresult";
-
var connected = Connect();
if (!connected) return Example.InvalidQueryConnection;
- var query = new Query();
try
{
- var command = new SqlCommand();
- command.Connection = _db;
- command.CommandTimeout = Timeout.Query;
- command.CommandText = sql;
- if (parameters != null)
+ using (var command = new SqlCommand())
{
- foreach (var parameter in parameters)
+ command.Connection = _db;
+ command.CommandTimeout = _timeout.Query;
+ command.CommandText = sql;
+ if (parameters != null)
{
- if (parameter != null) command.Parameters.Add(parameter);
+ foreach (var parameter in parameters)
+ {
+ if (parameter != null) command.Parameters.Add(parameter);
+ }
}
- }
- using (var dataset = new DataSet())
- {
- using (var dataadapter = new SqlDataAdapter(sql, _db))
+ using (var ds = new DataSet())
{
- dataadapter.Fill(dataset, tablename);
- query.Table = dataset.Tables[tablename];
+ using (var da = new SqlDataAdapter(sql, _db))
+ {
+ const string name = "resule";
+ da.Fill(ds, name);
+ var table = ds.Tables[name];
+ return new Query(table, true);
+ }
}
}
- command.Dispose();
- query.Success = true;
}
catch (Exception exception)
{
- LogError("Query", exception, sql);
- query.Success = false;
- query.Exception = exception;
+ Logger.Error(nameof(SqlClient), "Query", exception, sql);
+ return new Query(exception);
}
- return query;
}
/// 执行。
@@ -210,119 +259,42 @@ namespace Apewer.Source
var connected = Connect();
if (!connected) return Example.InvalidExecuteConnection;
- var transaction = _db.BeginTransaction();
- var execute = new Execute();
+ var inTransaction = _transaction != null;
+ if (!inTransaction) Begin();
try
{
- var command = new SqlCommand();
- command.Connection = _db;
- command.Transaction = transaction;
- command.CommandTimeout = Timeout.Execute;
- command.CommandText = sql;
- if (parameters != null)
+ using (var command = new SqlCommand())
{
- foreach (var parameter in parameters)
+ command.Connection = _db;
+ command.Transaction = (SqlTransaction)_transaction;
+ command.CommandTimeout = _timeout.Execute;
+ command.CommandText = sql;
+ if (parameters != null)
{
- if (parameter != null) command.Parameters.Add(parameter);
+ foreach (var parameter in parameters)
+ {
+ if (parameter != null) command.Parameters.Add(parameter);
+ }
}
+ var rows = command.ExecuteNonQuery();
+ if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
+ return new Execute(true, rows);
}
- execute.Rows += command.ExecuteNonQuery();
- transaction.Commit();
- command.Dispose();
- execute.Success = true;
}
catch (Exception exception)
{
- try { transaction.Rollback(); } catch { }
- LogError("Execute", exception, sql);
- execute.Success = false;
- execute.Exception = exception;
+ Logger.Error(nameof(SqlClient), "Execute", exception, sql);
+ if (!inTransaction) Rollback();
+ return new Execute(exception);
}
- try { transaction.Dispose(); } catch { }
- return execute;
- }
-
- #endregion
-
- #region 属性。
-
- /// 获取当前的 SqlConnection 对象。
- public SqlConnection Connection
- {
- get { return _db; }
- }
-
- /// 获取或设置连接字符串。
- public string ConnectionString
- {
- get { return _connectionstring; }
- set { _connectionstring = value ?? ""; _address = ""; _store = ""; _user = ""; _pass = ""; }
- }
-
- /// 获取或设置数据库服务器的地址。
- public string Address
- {
- get { return _address; }
- set { _address = value ?? ""; UpdateConnectString(); }
- }
-
- /// 获取或设置数据库名称。
- public string Store
- {
- get { return _store; }
- set { _store = value ?? ""; UpdateConnectString(); }
- }
-
- /// 获取或设置用于连接数据库服务器的用户名,为空则使用 Windows 用户登录。
- public string User
- {
- get { return _user; }
- set { _user = value ?? ""; UpdateConnectString(); }
- }
-
- /// 获取或设置用于连接数据库服务器的密码。
- public string Pass
- {
- get { return _pass; }
- set { _pass = value ?? ""; UpdateConnectString(); }
- }
-
- /// 获取或设置超时。
- public Timeout Timeout
- {
- get { return _timeout; }
- set { _timeout = value; }
}
#endregion
- #region 方法。
-
- /// 指定连接凭据后,是否符合连接要求。
- public bool Proven()
- {
- return Proven(_address, _store, _user, _pass);
- }
-
- private void UpdateConnectString()
- {
- _connectionstring = "";
- _connectionstring += "data source = " + _address + "; ";
- _connectionstring += "initial catalog = " + _store + "; ";
- if (string.IsNullOrEmpty(User))
- {
- _connectionstring += "integrated security = sspi; ";
- }
- else
- {
- _connectionstring += "user id = " + _user + "; ";
- if (!string.IsNullOrEmpty(_pass)) _connectionstring += "password = " + _pass + "; ";
- }
- _connectionstring += "connection timeout = " + Timeout.Connect.ToString() + ";";
- }
+ #region ORM
/// 查询数据库中的所有表名。
- public List TableNames()
+ public string[] TableNames()
{
var list = new List();
if (Connect())
@@ -337,11 +309,11 @@ namespace Apewer.Source
}
query.Dispose();
}
- return list;
+ return list.ToArray();
}
/// 查询数据库实例中的所有数据库名。
- public List StoreNames()
+ public string[] StoreNames()
{
var list = new List();
if (Connect())
@@ -360,11 +332,11 @@ namespace Apewer.Source
}
query.Dispose();
}
- return list;
+ return list.ToArray();
}
/// 查询表中的所有列名。
- public List ColumnNames(string tableName)
+ public string[] ColumnNames(string tableName)
{
var list = new List();
if (Connect())
@@ -380,21 +352,17 @@ namespace Apewer.Source
}
query.Dispose();
}
- return list;
+ return list.ToArray();
}
/// 创建表,当表不存在时创建表,当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。
public string Initialize() where T : class, IRecord, new() => Initialize(typeof(T));
- /// 创建表,当表不存在时创建表,当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。
- public string Initialize(Record model) => model == null ? "参数无效。" : Initialize(model);
-
/// 创建表,当表不存在时创建表,当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。
public string Initialize(Type model)
{
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(model); }
- catch (Exception exception) { return exception.Message; }
+ var structure = TableStructure.Parse(model);
+ if (structure == null) return "无法解析记录模型。";
// 连接数据库。
if (!Connect()) return "连接数据库失败。";
@@ -402,9 +370,9 @@ namespace Apewer.Source
// 检查现存表。
var exists = false;
var tables = TableNames();
- if (tables.Count > 0)
+ if (tables.Length > 0)
{
- var lower = structure.Table.ToLower();
+ var lower = structure.Name.ToLower();
foreach (var table in tables)
{
if (TextUtility.IsBlank(table)) continue;
@@ -419,8 +387,8 @@ namespace Apewer.Source
if (exists)
{
// 获取已存在的列名。
- var columns = ColumnNames(structure.Table);
- if (columns.Count > 0)
+ var columns = ColumnNames(structure.Name);
+ if (columns.Length > 0)
{
var lower = new List();
foreach (var column in columns)
@@ -428,11 +396,11 @@ namespace Apewer.Source
if (TextUtility.IsBlank(column)) continue;
lower.Add(column.ToLower());
}
- columns = lower;
+ columns = lower.ToArray();
}
// 增加列。
- foreach (var column in structure.Columns.Values)
+ foreach (var column in structure.Columns)
{
// 检查 Independent 特性。
if (structure.Independent && column.Independent) continue;
@@ -444,100 +412,83 @@ namespace Apewer.Source
var type = GetColumnDeclaration(column);
if (type == TextUtility.Empty) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
- var sql = TextUtility.Merge("alter table [", structure.Table, "] add ", type, "; ");
+ var sql = TextUtility.Merge("alter table [", structure.Name, "] add ", type, "; ");
var execute = Execute(sql);
- if (execute.Success == false) return execute.Error;
+ if (execute.Success == false) return execute.Message;
}
return TextUtility.Empty;
}
else
{
var sqlcolumns = new List();
- foreach (var kvp in structure.Columns)
+ foreach (var column in structure.Columns)
{
- var property = kvp.Key;
- var column = kvp.Value;
-
// 检查 Independent 特性。
if (structure.Independent && column.Independent) continue;
var type = GetColumnDeclaration(column);
- if (!column.Independent && property == "Key") type = type + " primary key";
+ if (!column.Independent && column.Property.Name == "Key") type = type + " primary key";
if (type == TextUtility.Empty) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
sqlcolumns.Add(type);
}
- var sql = TextUtility.Merge("create table [", structure.Table, "](", string.Join(", ", sqlcolumns.ToArray()), "); ");
+ var sql = TextUtility.Merge("create table [", structure.Name, "](", string.Join(", ", sqlcolumns.ToArray()), "); ");
var execute = Execute(sql);
if (execute.Success) return TextUtility.Empty;
- return execute.Error;
+ return execute.Message;
}
}
- /// 插入记录。成功时候返回空字符串,发生异常时返回异常信息。
+ /// 插入记录。返回错误信息。
public string Insert(IRecord record)
{
if (record == null) return "参数无效。";
- var type = record.GetType();
-
record.FixProperties();
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(record); }
- catch (Exception exception) { return exception.Message; }
-
- var parameters = structure.CreateDataParameters(record, CreateDataParameter);
-
- var sql = GenerateInsertStatement(structure.Table, parameters);
+ var structure = TableStructure.Parse(record.GetType());
+ if (structure == null) return "无法解析记录模型。";
+ var parameters = structure.CreateParameters(record, CreateDataParameter);
+ var sql = GenerateInsertStatement(structure.Name, parameters);
var execute = Execute(sql, parameters);
if (execute.Success) return TextUtility.Empty;
- return execute.Error;
+ return execute.Message;
}
- ///
- /// 更新记录,实体中的 Created 和 Key 属性不被更新。成功时返回空字符串,发生异常时返回异常信息。
- /// 无法更新拥有 Independent 特性的模型。
- ///
+ /// 更新记录,实体中的 Key 属性不被更新。返回错误信息。
+ /// 无法更新带有 Independent 特性的模型(缺少 Key 属性)。
public string Update(IRecord record)
{
if (record == null) return "参数无效。";
- var type = record.GetType();
-
record.FixProperties();
record.SetUpdated();
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(record); }
- catch (Exception exception) { return exception.Message; }
-
- // 检查 Independent 特性。
- if (structure.Independent) return "无法更新拥有 Independent 特性的模型。";
-
- var parameters = structure.CreateDataParameters(record, CreateDataParameter, "_created", "_key");
-
- var sql = GenerateUpdateStatement(structure.Table, record.Key, parameters);
+ var structure = TableStructure.Parse(record.GetType());
+ if (structure == null) return "无法解析记录模型。";
+ if (structure.Independent) return "无法更新带有 Independent 特性的模型。";
+ var parameters = structure.CreateParameters(record, CreateDataParameter, "_key");
+ var sql = GenerateUpdateStatement(structure.Name, record.Key, parameters);
var execute = Execute(sql, parameters);
if (execute.Success) return TextUtility.Empty;
- return execute.Error;
+ return execute.Message;
}
/// 获取按指定语句查询到的所有记录。
- public Result> Query(Type model, string sql) => OrmHelper.Query(this, model, sql);
+ public Result Query(Type model, string sql) => OrmHelper.Query(this, model, sql);
/// 获取按指定语句查询到的所有记录。
- public Result> Query(string sql) where T : class, IRecord, new() => OrmHelper.Query(this, sql);
+ public Result Query(string sql) where T : class, IRecord, new() => OrmHelper.Query(this, sql);
/// 获取记录。
- public Result> Query(Type model, long flag = 0) => OrmHelper.Query(this, model, (tn) =>
+ public Result Query(Type model, long flag = 0) => OrmHelper.Query(this, model, (tn) =>
{
if (flag == 0) return $"select * from [{tn}]; ";
return $"select * from [{tn}] where _flag={flag}; ";
});
/// 获取记录。
- public Result> Query(long flag = 0) where T : class, IRecord, new() => OrmHelper.Query(this, (tn) =>
+ public Result Query(long flag = 0) where T : class, IRecord, new() => OrmHelper.Query(this, (tn) =>
{
if (flag == 0) return $"select * from [{tn}]; ";
return $"select * from [{tn}] where _flag={flag}; ";
@@ -558,66 +509,55 @@ namespace Apewer.Source
});
/// 查询有效的 Key 值。
- public Result> Keys(Type model, long flag = 0) => OrmHelper.Keys(this, model, (tn) =>
+ public Result Keys(Type model, long flag = 0) => OrmHelper.Keys(this, model, (tn) =>
{
if (flag == 0) return $"select _key from [{tn}]; ";
return $"select _key from [{tn}] where _flag={flag}; ";
});
/// 查询有效的 Key 值。
- public Result> Keys(long flag = 0) where T : class, IRecord, new() => Keys(typeof(T), flag);
+ public Result Keys(long flag = 0) where T : class, IRecord, new() => Keys(typeof(T), flag);
#endregion
- #region 静态方法。
+ #region public static
+
+#if NETFRAMEWORK
- private static string GetColumnDeclaration(ColumnAttribute column)
+ /// 枚举本地网络中服务器的名称。
+ public static SqlServerSource[] EnumerateServer()
{
- var type = TextUtility.Empty;
- var vcolumn = column;
- var length = Math.Max(0, vcolumn.Length);
- switch (vcolumn.Type)
+ var list = new List();
+
+ // 表中列名:ServerName、InstanceName、IsClustered、Version。
+ using (var query = new Query(SqlDataSourceEnumerator.Instance.GetDataSources()))
{
- case ColumnType.Integer:
- type = "bigint";
- break;
- case ColumnType.Float:
- type = "float";
- break;
- case ColumnType.Bytes:
- type = "image";
- break;
- case ColumnType.DateTime:
- type = "datetime";
- break;
- case ColumnType.VarChar:
- type = TextUtility.Merge("varchar(", Math.Min(8000, length).ToString(), ")");
- break;
- case ColumnType.VarChar255:
- type = TextUtility.Merge("varchar(255)");
- break;
- case ColumnType.VarCharMax:
- type = TextUtility.Merge("varchar(max)");
- break;
- case ColumnType.Text:
- type = TextUtility.Merge("text");
- break;
- case ColumnType.NVarChar:
- type = TextUtility.Merge("nvarchar(", Math.Min(4000, length).ToString(), ")");
- break;
- case ColumnType.NVarChar255:
- type = TextUtility.Merge("nvarchar(255)");
- break;
- case ColumnType.NVarCharMax:
- type = TextUtility.Merge("nvarchar(max)");
- break;
- case ColumnType.NText:
- type = TextUtility.Merge("ntext");
- break;
- default:
- return TextUtility.Empty;
+ for (int i = 0; i < query.Rows; i++)
+ {
+ var item = new SqlServerSource();
+ item.ServerName = query.Text(i, "ServerName");
+ list.Add(item);
+ }
}
- return TextUtility.Merge("[", vcolumn.Field, "] ", type);
+ return list.ToArray();
+ }
+
+#endif
+
+ /// 指定的连接凭据是否符合连接要求,默认指定 master 数据库。
+ public static bool Proven(string address, string user, string pass) => Proven(address, "master", user, pass);
+
+ /// 指定的连接凭据是否符合连接要求。
+ public static bool Proven(string address, string store, string user, string pass)
+ {
+ var a = string.IsNullOrEmpty(address);
+ var s = string.IsNullOrEmpty(store);
+ var u = string.IsNullOrEmpty(user);
+ var p = string.IsNullOrEmpty(pass);
+ if (a) return false;
+ if (s) return false;
+ if (u && !p) return false;
+ return true;
}
/// 创建参数。
@@ -651,12 +591,12 @@ namespace Apewer.Source
vtype = SqlDbType.DateTime;
break;
case ColumnType.VarChar:
- case ColumnType.VarChar255:
+ case ColumnType.VarChar191:
case ColumnType.VarCharMax:
vtype = SqlDbType.VarChar;
break;
case ColumnType.NVarChar:
- case ColumnType.NVarChar255:
+ case ColumnType.NVarChar191:
case ColumnType.NVarCharMax:
vtype = SqlDbType.VarChar;
break;
@@ -679,9 +619,9 @@ namespace Apewer.Source
case ColumnType.NVarChar:
vsize = NumberUtility.Restrict(vsize, 0, 4000);
break;
- case ColumnType.VarChar255:
- case ColumnType.NVarChar255:
- vsize = NumberUtility.Restrict(vsize, 0, 255);
+ case ColumnType.VarChar191:
+ case ColumnType.NVarChar191:
+ vsize = NumberUtility.Restrict(vsize, 0, 191);
break;
default:
vsize = 0;
@@ -728,51 +668,60 @@ namespace Apewer.Source
return p;
}
- ///// 枚举本地网络中服务器的名称。
- //public static List EnumerateServer()
- //{
- // // 表中列名:ServerName、InstanceName、IsClustered、Version。
- // var table = SqlDataSourceEnumerator.Instance.GetDataSources();
- // var query = new Query();
- // query.Success = table != null;
- // query.Table = table;
- // var list = new List();
- // for (int i = 0; i < query.Rows; i++)
- // {
- // var sn = query.Text(i, "ServerName");
- // if (!string.IsNullOrEmpty(sn)) list.Add(sn);
- // }
- // query.Dispose();
- // return list;
- //}
-
- /// 指定的连接凭据是否符合连接要求。
- public static bool Proven(SqlClinet sqlserver)
- {
- return Proven(sqlserver._address, sqlserver._store, sqlserver._user, sqlserver._pass);
- }
+ #endregion
- /// 指定的连接凭据是否符合连接要求,默认指定 master 数据库。
- public static bool Proven(string address, string user, string pass) => Proven(address, "master", user, pass);
+ #region private
- /// 指定的连接凭据是否符合连接要求。
- public static bool Proven(string address, string store, string user, string pass)
+ static string GetColumnDeclaration(ColumnAttribute column)
{
- var a = string.IsNullOrEmpty(address);
- var s = string.IsNullOrEmpty(store);
- var u = string.IsNullOrEmpty(user);
- var p = string.IsNullOrEmpty(pass);
- if (a) return false;
- if (s) return false;
- if (u && !p) return false;
- return true;
+ var type = TextUtility.Empty;
+ var vcolumn = column;
+ var length = Math.Max(0, vcolumn.Length);
+ switch (vcolumn.Type)
+ {
+ case ColumnType.Integer:
+ type = "bigint";
+ break;
+ case ColumnType.Float:
+ type = "float";
+ break;
+ case ColumnType.Bytes:
+ type = "image";
+ break;
+ case ColumnType.DateTime:
+ type = "datetime";
+ break;
+ case ColumnType.VarChar:
+ type = TextUtility.Merge("varchar(", Math.Min(8000, length).ToString(), ")");
+ break;
+ case ColumnType.VarChar191:
+ type = TextUtility.Merge("varchar(191)");
+ break;
+ case ColumnType.VarCharMax:
+ type = TextUtility.Merge("varchar(max)");
+ break;
+ case ColumnType.Text:
+ type = TextUtility.Merge("text");
+ break;
+ case ColumnType.NVarChar:
+ type = TextUtility.Merge("nvarchar(", Math.Min(4000, length).ToString(), ")");
+ break;
+ case ColumnType.NVarChar191:
+ type = TextUtility.Merge("nvarchar(255)");
+ break;
+ case ColumnType.NVarCharMax:
+ type = TextUtility.Merge("nvarchar(max)");
+ break;
+ case ColumnType.NText:
+ type = TextUtility.Merge("ntext");
+ break;
+ default:
+ return TextUtility.Empty;
+ }
+ return TextUtility.Merge("[", vcolumn.Field, "] ", type);
}
- #endregion
-
- #region Linq Utility
-
- private static string GetParameterName(string parameter)
+ static string GetParameterName(string parameter)
{
var name = TextUtility.AntiInject(parameter, 255);
if (name.StartsWith("@") && name.Length > 1)
@@ -782,7 +731,7 @@ namespace Apewer.Source
return name;
}
- private static string GetParameterName(IDataParameter parameter)
+ static string GetParameterName(IDataParameter parameter)
{
var name = TextUtility.Empty;
if (parameter != null)
@@ -792,7 +741,7 @@ namespace Apewer.Source
return name;
}
- private static List GetParametersNames(IEnumerable parameters)
+ static string[] GetParametersNames(IEnumerable parameters)
{
var columns = new List();
if (parameters != null)
@@ -805,10 +754,10 @@ namespace Apewer.Source
columns.Add(name);
}
}
- return columns;
+ return columns.ToArray();
}
- private static string GenerateInsertStatement(string table, List columns)
+ static string GenerateInsertStatement(string table, string[] columns)
{
var result = TextUtility.Empty;
var vtable = TextUtility.AntiInject(table, 255);
@@ -835,7 +784,7 @@ namespace Apewer.Source
return result;
}
- private static string GenerateUpdateStatement(string table, string key, List columns)
+ static string GenerateUpdateStatement(string table, string key, string[] columns)
{
var result = TextUtility.Empty;
var vtable = TextUtility.AntiInject(table, 255);
@@ -858,14 +807,14 @@ namespace Apewer.Source
/// 生成 INSERT INTO 语句。表名必须有效,无有效参数时将获取空结果。
///
///
- private static string GenerateInsertStatement(string table, IEnumerable parameters)
+ static string GenerateInsertStatement(string table, IEnumerable parameters)
{
if (table == null) throw new ArgumentNullException(nameof(table));
var tableName = TextUtility.AntiInject(table, 255);
if (TextUtility.IsBlank(tableName)) throw new ArgumentException("表名无效。", nameof(table));
var vcolumns = GetParametersNames(parameters);
- if (vcolumns.Count < 1) return TextUtility.Empty;
+ if (vcolumns.Length < 1) return TextUtility.Empty;
return GenerateInsertStatement(tableName, vcolumns);
}
@@ -873,7 +822,7 @@ namespace Apewer.Source
/// 生成 UPDATE 语句,键字段名为“_key”。表名必须有效,键值必须有效,无有效参数时将获取空结果。
///
///
- private static string GenerateUpdateStatement(string table, string key, IEnumerable parameters)
+ static string GenerateUpdateStatement(string table, string key, IEnumerable parameters)
{
if (table == null) throw new ArgumentNullException(nameof(table));
var t = TextUtility.AntiInject(table, 255);
@@ -884,7 +833,7 @@ namespace Apewer.Source
if (TextUtility.IsBlank(k)) throw new ArgumentException("键值无效。", nameof(table));
var columes = GetParametersNames(parameters);
- if (columes.Count < 1) return TextUtility.Empty;
+ if (columes.Length < 1) return TextUtility.Empty;
return GenerateUpdateStatement(t, k, columes);
}
@@ -894,5 +843,3 @@ namespace Apewer.Source
}
}
-
-#endif
diff --git a/Apewer.Source/Source/SqlServerSouce.cs b/Apewer.Source/Source/SqlServerSouce.cs
new file mode 100644
index 0000000..561caa8
--- /dev/null
+++ b/Apewer.Source/Source/SqlServerSouce.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Apewer.Source
+{
+
+ /// 枚举的 SQL Server 源。
+ public class SqlServerSource
+ {
+
+ ///
+ public string ServerName { get; set; }
+
+ ///
+ public string InstanceName { get; set; }
+
+ ///
+ public string IsClustered { get; set; }
+
+ ///
+ public string Version { get; set; }
+
+ }
+
+}
diff --git a/Apewer.Source/Source/Sqlite.cs b/Apewer.Source/Source/Sqlite.cs
index fc60778..bb0b09d 100644
--- a/Apewer.Source/Source/Sqlite.cs
+++ b/Apewer.Source/Source/Sqlite.cs
@@ -1,8 +1,9 @@
-/* 2021.09.23 */
+/* 2021.10.14 */
using System;
using System.Collections.Generic;
using System.Data;
+using System.Data.Common;
using System.Data.SQLite;
using System.Text;
//using Mono.Data.Sqlite;
@@ -11,73 +12,50 @@ namespace Apewer.Source
{
/// 用于快速连接 SQLite 数据库的辅助。
- public class Sqlite : IDatabase
+ public class Sqlite : IDbClient
{
- #region 变量定义。
+ #region 基础
- private SQLiteConnection _db = null;
- private object _locker = new object();
-
- private Timeout _timeout = new Timeout();
+ private Timeout _timeout = null;
private string _connstring = "";
private string _path = "";
private string _pass = "";
- private byte[] _passdata = BytesUtility.Empty;
-
- #endregion
-
- #region this
-
- private void VarInit(string path, Timeout timeout, string pass, byte[] passData)
- {
- _path = path ?? "";
- _passdata = (passData == null) ? BytesUtility.Empty : passData;
- _pass = pass ?? "";
- _timeout = timeout;
- }
-
- /// 连接内存。
- public Sqlite() => VarInit(Memory, new Timeout(), null, null);
- /// 连接指定文件。
- public Sqlite(string path) => VarInit(path, new Timeout(), null, null);
-
- /// 连接指定文件。
- private Sqlite(string path, byte[] passData) => VarInit(path, new Timeout(), null, passData);
-
- /// 连接指定文件。
- public Sqlite(string path, string pass) => VarInit(path, new Timeout(), pass, null);
-
- /// 连接指定文件。
- public Sqlite(string path, Timeout timeout) => VarInit(path, timeout, null, null);
-
- #endregion
-
- #region 日志。
+ private object _locker = new object();
/// 获取或设置日志记录。
public Logger Logger { get; set; }
- private void LogError(string action, Exception ex, string addtion)
- {
- var logger = Logger;
- if (logger != null) logger.Error(this, "SQLite", action, ex.GetType().FullName, ex.Message, addtion);
- }
+ /// 超时设定。
+ public Timeout Timeout { get => _timeout; }
- private void LogError(string action, string message)
+ /// 创建连接实例。
+ /// 注意:
- 构造函数不会创建不存在的文件;
- 参数 path 为文件路径,指定为空时将使用 :memory: 作为路径连接内存。
+ public Sqlite(string path = null, string pass = null, Timeout timeout = null)
{
- var logger = Logger;
- if (logger != null) logger.Error(this, "SQLite", action, message);
+ _timeout = timeout ?? Timeout.Default;
+ _path = path.IsEmpty() ? Memory : path;
+ _pass = pass;
+ if (pass.IsEmpty()) _connstring = $"data source='{_path}'; password={_pass}; version=3; ";
+ else _connstring = $"data source='{_path}'; password={_pass}; version=3; ";
}
#endregion
- #region 实现接口。
+ #region 连接
- /// 数据库是否已经连接。
+ private SQLiteConnection _db = null;
+
+ /// 数据库已经连接。
public bool Online { get => _db != null && _db.State == ConnectionState.Open; }
+ /// 连接字符串。
+ public string ConnectionString { get => _connstring; }
+
+ /// 获取当前的 SQLiteConnection 对象。
+ public IDbConnection Connection { get => _db; }
+
/// 连接数据库,若未连接则尝试连接。
/// 是否已连接。
public bool Connect()
@@ -86,10 +64,6 @@ namespace Apewer.Source
{
_db = new SQLiteConnection();
_db.ConnectionString = ConnectionString;
- //if (string.IsNullOrEmpty(_connstring) && string.IsNullOrEmpty(_pass) && (_passdata.Length > 0))
- //{
- // _db.SetPassword(_pass);
- //}
}
else
{
@@ -106,7 +80,7 @@ namespace Apewer.Source
}
catch (Exception ex)
{
- LogError("Connection", ex, _db.ConnectionString);
+ Logger.Error(nameof(Sqlite), "Connection", ex, _db.ConnectionString);
Close();
return false;
}
@@ -117,6 +91,11 @@ namespace Apewer.Source
{
if (_db != null)
{
+ if (_transaction != null)
+ {
+ if (_autocommit) Commit();
+ else Rollback();
+ }
lock (_locker)
{
_db.Dispose();
@@ -128,6 +107,78 @@ namespace Apewer.Source
/// 关闭连接,释放对象所占用的系统资源,并清除连接信息。
public void Dispose() { Close(); }
+ #endregion
+
+ #region Transaction
+
+ private IDbTransaction _transaction = null;
+ private bool _autocommit = false;
+
+ /// 启动事务。
+ public string Begin(bool commit = true) => Begin(commit, null);
+
+ /// 启动事务。
+ public string Begin(bool commit, Class isolation)
+ {
+ if (!Connect()) return "未连接。";
+ if (_transaction != null) return "存在已启动的事务,无法再次启动。";
+ try
+ {
+ _transaction = isolation ? _db.BeginTransaction(isolation.Value) : _db.BeginTransaction();
+ _autocommit = commit;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(nameof(Sqlite), "Begin", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ /// 提交事务。
+ public string Commit()
+ {
+ if (_transaction == null) return "事务不存在。";
+ try
+ {
+ _transaction.Commit();
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ Logger.Error(nameof(Sqlite), "Commit", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ /// 从挂起状态回滚事务。
+ public string Rollback()
+ {
+ if (_transaction == null) return "事务不存在。";
+ try
+ {
+ _transaction.Rollback();
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ return null;
+ }
+ catch (Exception ex)
+ {
+ RuntimeUtility.Dispose(_transaction);
+ _transaction = null;
+ Logger.Error(nameof(Sqlite), "Rollback", ex.Message());
+ return ex.Message();
+ }
+ }
+
+ #endregion
+
+ #region SQL
+
/// 查询。
public IQuery Query(string sql) => Query(sql, null);
@@ -136,43 +187,41 @@ namespace Apewer.Source
{
if (string.IsNullOrEmpty(sql)) return Example.InvalidQueryStatement;
- const string table = "result";
-
var connected = Connect();
if (!connected) return Example.InvalidQueryConnection;
var query = new Query();
try
{
- var command = new SQLiteCommand();
- command.Connection = _db;
- command.CommandTimeout = Timeout.Query;
- command.CommandText = sql;
- if (parameters != null)
+ using (var command = new SQLiteCommand())
{
- foreach (var p in parameters)
+ command.Connection = _db;
+ command.CommandTimeout = _timeout.Query;
+ command.CommandText = sql;
+ if (parameters != null)
{
- if (p != null) command.Parameters.Add(p);
+ foreach (var p in parameters)
+ {
+ if (p != null) command.Parameters.Add(p);
+ }
}
- }
- using (var dataset = new DataSet())
- {
- using (var da = new SQLiteDataAdapter(sql, _db))
+ using (var dataset = new DataSet())
{
- da.Fill(dataset, table);
- query.Table = dataset.Tables[table];
+ using (var da = new SQLiteDataAdapter(sql, _db))
+ {
+ const string name = "result";
+ da.Fill(dataset, name);
+ var table = dataset.Tables[name];
+ return new Query(table);
+ }
}
}
- command.Dispose();
- query.Success = true;
}
catch (Exception ex)
{
- LogError("Query", ex, sql);
- query.Success = false;
- query.Exception = ex;
+ Logger.Error(nameof(Sqlite), "Query", ex, sql);
+ return new Query(ex);
}
- return query;
}
/// 执行单条 Transact-SQL 语句。
@@ -188,36 +237,34 @@ namespace Apewer.Source
lock (_locker)
{
- var transaction = _db.BeginTransaction();
- var execute = new Execute();
+ var inTransaction = _transaction != null;
+ if (!inTransaction) Begin();
try
{
- var command = new SQLiteCommand();
- command.Connection = _db;
- command.Transaction = transaction;
- command.CommandTimeout = Timeout.Execute;
- command.CommandText = sql;
- if (parameters != null)
+ using (var command = new SQLiteCommand())
{
- foreach (var p in parameters)
+ command.Connection = _db;
+ command.Transaction = (SQLiteTransaction)_transaction;
+ command.CommandTimeout = _timeout.Execute;
+ command.CommandText = sql;
+ if (parameters != null)
{
- if (p != null) command.Parameters.Add(p);
+ foreach (var p in parameters)
+ {
+ if (p != null) command.Parameters.Add(p);
+ }
}
+ var rows = command.ExecuteNonQuery();
+ if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
+ return new Execute(true, rows);
}
- execute.Rows += command.ExecuteNonQuery();
- transaction.Commit();
- command.Dispose();
- execute.Success = true;
}
catch (Exception ex)
{
- try { transaction.Rollback(); } catch { }
- LogError("Execute", ex, sql);
- execute.Success = false;
- execute.Exception = ex;
+ Logger.Error(nameof(Sqlite), "Execute", ex, sql);
+ if (!inTransaction) Rollback();
+ return new Execute(ex);
}
- try { transaction.Dispose(); } catch { }
- return execute;
}
}
@@ -225,72 +272,12 @@ namespace Apewer.Source
#region 属性。
- /// 获取当前的 SQLiteConnection 对象。
- public IDbConnection Connection { get => _db; }
-
- /// 获取或设置超时。
- public Timeout Timeout { get => _timeout; set => _timeout = value; }
-
- /// 获取或设置连接字符串,连接字符串非空时将忽略 Path 属性。数据库在线时无法设置。
- public string ConnectionString
- {
- get
- {
- if (string.IsNullOrEmpty(_connstring))
- {
- var temp = new StringBuilder();
- temp.Append("data source='", _path, "'; version=3; ");
- if (!string.IsNullOrEmpty(_pass)) temp.Append("password=", _pass, "; ");
- return temp.ToString();
- }
- else return _connstring;
- }
- set
- {
- if (Online) return;
- _connstring = string.IsNullOrEmpty(value) ? "" : value;
- }
- }
-
- /// 获取或设置数据库路径(文件或内存)。数据库在线时无法设置。
- public string Path
- {
- get { return _path; }
- set
- {
- if (Online) return;
- _path = string.IsNullOrEmpty(value) ? "" : value;
- }
- }
-
- /// 获取或设置数据库密码。数据库在线时无法设置。
- public string Password
- {
- get { return _pass; }
- set
- {
- if (Online) return;
- _pass = string.IsNullOrEmpty(value) ? "" : value;
- }
- }
-
- /// 获取或设置数据库密码。数据库在线时无法设置。
- private byte[] PasswordData
- {
- get { return _passdata; }
- set
- {
- if (Online) return;
- _passdata = (value == null) ? BytesUtility.Empty : value;
- }
- }
-
/// 保存当前数据库到文件,若文件已存在则将重写文件。
public bool Save(string path, string pass = null)
{
if (!StorageUtility.CreateFile(path, 0, true))
{
- LogError("Save", TextUtility.Merge("创建文件 ", path, " 失败。"));
+ Logger.Error(nameof(Sqlite), "Save", TextUtility.Merge("创建文件 ", path, " 失败。"));
return false;
}
@@ -311,10 +298,10 @@ namespace Apewer.Source
#endregion
- #region ORM。
+ #region ORM
/// 查询数据库中的所有表名。
- public List TableNames()
+ public string[] TableNames()
{
var list = new List();
if (Connect())
@@ -329,11 +316,11 @@ namespace Apewer.Source
}
query.Dispose();
}
- return list;
+ return list.ToArray();
}
/// 查询数据库中的所有视图名。
- public List ViewNames()
+ public string[] ViewNames()
{
var list = new List();
if (Connect())
@@ -348,11 +335,11 @@ namespace Apewer.Source
}
query.Dispose();
}
- return list;
+ return list.ToArray();
}
/// 查询表中的所有列名。
- public List ColumnNames(string table)
+ public string[] ColumnNames(string table)
{
var list = new List();
if (Connect())
@@ -369,7 +356,7 @@ namespace Apewer.Source
}
}
}
- return list;
+ return list.ToArray();
}
/// 创建表,不修改已存在表。成功时返回空字符串,发生异常时返回异常信息。
@@ -381,9 +368,8 @@ namespace Apewer.Source
/// 创建表,不修改已存在表。当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。
public string Initialize(Type model)
{
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(model); }
- catch (Exception exception) { return exception.Message; }
+ var structure = TableStructure.Parse(model);
+ if (structure == null) return "无法解析记录模型。";
// 连接数据库。
if (!Connect()) return "连接数据库失败。";
@@ -391,9 +377,9 @@ namespace Apewer.Source
// 检查现存表。
var exists = false;
var tables = TableNames();
- if (tables.Count > 0)
+ if (tables.Length > 0)
{
- var lower = structure.Table.ToLower();
+ var lower = structure.Name.ToLower();
foreach (var table in tables)
{
if (TextUtility.IsBlank(table)) continue;
@@ -412,73 +398,69 @@ namespace Apewer.Source
else
{
var sqlcolumns = new List();
- foreach (var column in structure.Columns.Values)
+ foreach (var column in structure.Columns)
{
var type = GetColumnDeclaration(column);
if (type == TextUtility.Empty) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
sqlcolumns.Add(type);
}
- var sql = TextUtility.Merge("create table [", structure.Table, "](", TextUtility.Join(", ", sqlcolumns), "); ");
+ var sql = TextUtility.Merge("create table [", structure.Name, "](", TextUtility.Join(", ", sqlcolumns), "); ");
var execute = Execute(sql);
if (execute.Success) return TextUtility.Empty;
- return execute.Error;
+ return execute.Message;
}
}
- /// 插入记录。成功时候返回空字符串,发生异常时返回异常信息。
+ /// 插入记录。返回错误信息。
public string Insert(IRecord record)
{
if (record == null) return "参数无效。";
record.FixProperties();
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(record); }
- catch (Exception exception) { return exception.Message; }
-
- var parameters = structure.CreateDataParameters(record, CreateDataParameter);
-
- var sql = GenerateInsertStatement(structure.Table, (IEnumerable)parameters);
+ var structure = TableStructure.Parse(record.GetType());
+ if (structure == null) return "无法解析记录模型。";
+ var parameters = structure.CreateParameters(record, CreateDataParameter);
+ var sql = GenerateInsertStatement(structure.Name, (IEnumerable)parameters);
var execute = Execute(sql, parameters);
if (execute.Success && execute.Rows > 0) return TextUtility.Empty;
- return execute.Error;
+ return execute.Message;
}
- /// 更新记录,实体中的 Created 和 Key 属性不被更新。成功时返回空字符串,发生异常时返回异常信息。
+ /// 更新记录,实体中的 Key 属性不被更新。返回错误信息。
+ /// 无法更新带有 Independent 特性的模型(缺少 Key 属性)。
public string Update(IRecord record)
{
if (record == null) return "参数无效。";
record.FixProperties();
record.SetUpdated();
- var structure = null as TableStructure;
- try { structure = TableStructure.ParseModel(record); }
- catch (Exception exception) { return exception.Message; }
-
- var parameters = structure.CreateDataParameters(record, CreateDataParameter, "_created", "_key");
-
- var sql = GenerateUpdateStatement(structure.Table, record.Key, parameters);
+ var structure = TableStructure.Parse(record.GetType());
+ if (structure == null) return "无法解析记录模型。";
+ if (structure.Independent) return "无法更新带有 Independent 特性的模型。";
+ var parameters = structure.CreateParameters(record, CreateDataParameter, "_key");
+ var sql = GenerateUpdateStatement(structure.Name, record.Key, parameters);
var execute = Execute(sql, parameters);
if (execute.Success && execute.Rows > 0) return TextUtility.Empty;
- return execute.Error;
+ return execute.Message;
}
/// 获取按指定语句查询到的所有记录。
- public Result> Query(Type model, string sql) => OrmHelper.Query(this, model, sql);
+ public Result Query(Type model, string sql) => OrmHelper.Query(this, model, sql);
/// 获取按指定语句查询到的所有记录。
- public Result> Query(string sql) where T : class, IRecord, new() => OrmHelper.Query(this, sql);
+ public Result Query(string sql) where T : class, IRecord, new() => OrmHelper.Query(this, sql);
/// 查询多条记录。
- public Result> Query(Type model, long flag = 0) => OrmHelper.Query(this, model, (tn) =>
+ public Result Query(Type model, long flag = 0) => OrmHelper.Query(this, model, (tn) =>
{
if (flag == 0) return $"select * from [{tn}]; ";
return $"select * from [{tn}] where _flag={flag}; ";
});
/// 查询多条记录。
- public Result> Query(long flag = 0) where T : class, IRecord, new() => OrmHelper.Query(this, (tn) =>
+ public Result Query(long flag = 0) where T : class, IRecord, new() => OrmHelper.Query(this, (tn) =>
{
if (flag == 0) return $"select * from [{tn}]; ";
return $"select * from [{tn}] where _flag={flag}; ";
@@ -499,14 +481,14 @@ namespace Apewer.Source
});
/// 获取指定类型的主键,按 Flag 属性筛选。
- public Result> Keys(Type model, long flag = 0) => OrmHelper.Keys(this, model, (tn) =>
+ public Result Keys(Type model, long flag = 0) => OrmHelper.Keys(this, model, (tn) =>
{
if (flag == 0) return $"select _key from [{tn}] where _flag={flag}; ";
return $"select _key from [{tn}]; ";
});
/// >获取指定类型的主键,按 Flag 属性筛选。
- public Result> Keys(long flag = 0) where T : class, IRecord, new() => Keys(typeof(T), flag);
+ public Result Keys(long flag = 0) where T : class, IRecord, new() => Keys(typeof(T), flag);
#endregion
@@ -553,13 +535,13 @@ namespace Apewer.Source
case ColumnType.Float:
return "float";
case ColumnType.VarChar:
- case ColumnType.VarChar255:
+ case ColumnType.VarChar191:
case ColumnType.VarCharMax:
return "varchar";
case ColumnType.Text:
return "text";
case ColumnType.NVarChar:
- case ColumnType.NVarChar255:
+ case ColumnType.NVarChar191:
case ColumnType.NVarCharMax:
return "nvarchar";
case ColumnType.NText:
@@ -585,9 +567,11 @@ namespace Apewer.Source
type = "real";
break;
case ColumnType.VarChar:
- case ColumnType.VarChar255:
type = TextUtility.Merge("varchar(", length, ")");
break;
+ case ColumnType.VarChar191:
+ type = TextUtility.Merge("varchar(191)");
+ break;
case ColumnType.VarCharMax:
type = TextUtility.Merge("varchar(255)");
break;
@@ -595,9 +579,11 @@ namespace Apewer.Source
type = TextUtility.Merge("text");
break;
case ColumnType.NVarChar:
- case ColumnType.NVarChar255:
type = TextUtility.Merge("nvarchar(", length, ")");
break;
+ case ColumnType.NVarChar191:
+ type = TextUtility.Merge("nvarchar(191)");
+ break;
case ColumnType.NVarCharMax:
type = TextUtility.Merge("nvarchar(255)");
break;
@@ -636,9 +622,11 @@ namespace Apewer.Source
case ColumnType.NVarChar:
s = NumberUtility.Restrict(s, 0, 4000);
break;
- case ColumnType.VarChar255:
+ case ColumnType.VarChar191:
+ case ColumnType.NVarChar191:
+ s = NumberUtility.Restrict(s, 0, 191);
+ break;
case ColumnType.VarCharMax:
- case ColumnType.NVarChar255:
case ColumnType.NVarCharMax:
s = NumberUtility.Restrict(s, 0, 255);
break;
@@ -742,7 +730,22 @@ namespace Apewer.Source
#endregion
- #region ORM
+ #region 生成 SQL 语句
+
+ /// 生成 INSERT INTO 语句。表名必须有效,无有效参数时将获取空结果。
+ ///
+ ///
+ public static string GenerateInsertStatement(string table, IEnumerable parameters)
+ {
+ if (table == null) throw new ArgumentNullException(nameof(table));
+ var t = TextUtility.AntiInject(table, 255);
+ if (TextUtility.IsBlank(t)) throw new ArgumentException("表名无效。", nameof(table));
+
+ var cs = GetParametersNames(parameters);
+ if (cs.Count < 1) return TextUtility.Empty;
+
+ return GenerateInsertStatement(t, cs);
+ }
private static string GetParameterName(string parameter)
{
@@ -807,21 +810,6 @@ namespace Apewer.Source
return r;
}
- /// 生成 INSERT INTO 语句。表名必须有效,无有效参数时将获取空结果。
- ///
- ///
- public static string GenerateInsertStatement(string table, IEnumerable parameters)
- {
- if (table == null) throw new ArgumentNullException(nameof(table));
- var t = TextUtility.AntiInject(table, 255);
- if (TextUtility.IsBlank(t)) throw new ArgumentException("表名无效。", nameof(table));
-
- var cs = GetParametersNames(parameters);
- if (cs.Count < 1) return TextUtility.Empty;
-
- return GenerateInsertStatement(t, cs);
- }
-
private static string GenerateUpdateStatement(string table, string key, List columns)
{
var result = TextUtility.Empty;
diff --git a/Apewer.Web/Internals/ApiHelper.cs b/Apewer.Web/Internals/ApiHelper.cs
index 0df0df9..23e4d8b 100644
--- a/Apewer.Web/Internals/ApiHelper.cs
+++ b/Apewer.Web/Internals/ApiHelper.cs
@@ -301,7 +301,7 @@ namespace Apewer.Internals
#region Response
- static StringPairs MergeHeaders(ApiOptions options, ApiResponse response)
+ static StringPairs PrepareHeaders(ApiOptions options, ApiResponse response)
{
var merged = new StringPairs();
if (options != null)
@@ -322,6 +322,12 @@ namespace Apewer.Internals
{
merged.Add("X-Content-Type-Options", "nosniff");
}
+
+ // 用于客户端,当前页面使用 HTTPS 时,将资源升级为 HTTPS。
+ if (options.UpgradeHttps)
+ {
+ merged.Add("Content-Security-Policy", "upgrade-insecure-requests");
+ }
}
if (response != null)
{
@@ -397,7 +403,7 @@ namespace Apewer.Internals
var preOutput = provider.PreWrite();
if (!string.IsNullOrEmpty(preOutput)) return;
- var headers = MergeHeaders(options, null);
+ var headers = PrepareHeaders(options, null);
foreach (var header in headers) provider.SetHeader(header.Key, header.Value);
provider.SetCache(0);
@@ -414,7 +420,7 @@ namespace Apewer.Internals
if (!string.IsNullOrEmpty(preOutput)) return;
// 设置头。
- var headers = MergeHeaders(options, null);
+ var headers = PrepareHeaders(options, null);
foreach (var header in headers) provider.SetHeader(header.Key, header.Value);
var model = response.Model;
diff --git a/Apewer.Web/Web/ApiEntries.cs b/Apewer.Web/Web/ApiEntries.cs
index 6fe980d..4101391 100644
--- a/Apewer.Web/Web/ApiEntries.cs
+++ b/Apewer.Web/Web/ApiEntries.cs
@@ -72,7 +72,7 @@ namespace Apewer.Web
public static ApiEntries From(Assembly assembly)
{
if (assembly == null) return null;
- var types = RuntimeUtility.GetTypes(assembly, true);
+ var types = RuntimeUtility.GetTypes(assembly, false);
var dict = new Dictionary();
foreach (var type in types)
{
diff --git a/Apewer.Web/Web/ApiProcessor.cs b/Apewer.Web/Web/ApiProcessor.cs
index 4477099..f843e38 100644
--- a/Apewer.Web/Web/ApiProcessor.cs
+++ b/Apewer.Web/Web/ApiProcessor.cs
@@ -261,6 +261,14 @@ namespace Apewer.Web
return;
}
+ // 未知类型,尝试 Json 类型。
+ var json = result as Json;
+ if (json != null)
+ {
+ response.Data = json;
+ return;
+ }
+
// 未知返回类型,无法明确输出格式,忽略。
}
else
diff --git a/Apewer.Web/Web/ApiProgram.cs b/Apewer.Web/Web/ApiProgram.cs
index e1f9def..0a88a60 100644
--- a/Apewer.Web/Web/ApiProgram.cs
+++ b/Apewer.Web/Web/ApiProgram.cs
@@ -17,13 +17,13 @@ namespace Apewer.Web
private static ApiInvoker _invoker = new ApiInvoker() { Logger = new Logger(), Options = new ApiOptions() };
/// API 选项。
- protected static ApiOptions Options { get => _invoker.Options; }
+ public static ApiOptions Options { get => _invoker.Options; }
/// 日志记录器。
- protected static Logger Logger { get => _invoker.Logger; }
+ public static Logger Logger { get => _invoker.Logger; }
/// 获取或设置 API 入口。
- protected static ApiEntries Entries { get => _invoker.Entries; set => _invoker.Entries = value; }
+ public static ApiEntries Entries { get => _invoker.Entries; set => _invoker.Entries = value; }
private Action _initializer = null;
diff --git a/Apewer/ArrayBuilder.cs b/Apewer/ArrayBuilder.cs
index 0a490ad..352a56a 100644
--- a/Apewer/ArrayBuilder.cs
+++ b/Apewer/ArrayBuilder.cs
@@ -6,7 +6,7 @@ namespace Apewer
{
/// 数组构建器。
- public class ArrayBuilder
+ public sealed class ArrayBuilder
{
private T[] _array;
@@ -35,6 +35,25 @@ namespace Apewer
if (_count > 0) Array.Copy(old._array, _array, _count);
}
+ /// 获取或设置指定位置的元素,索引器范围为 [0, Length)。
+ ///
+ public T this[int index]
+ {
+ get
+ {
+ if (index < 0 || index >= _count) throw new ArgumentOutOfRangeException("索引超出了当前数组的范围。");
+ return _array[index];
+ }
+ set
+ {
+ if (index < 0 || index >= _count) throw new ArgumentOutOfRangeException("索引超出了当前数组的范围。");
+ _array[index] = value;
+ }
+ }
+
+ /// 缓冲区的容量。
+ public int Capacity { get => _capacity; }
+
/// 当前的元素数量。
public int Length { get => _count; }
@@ -95,6 +114,13 @@ namespace Apewer
_count += length;
}
+ /// 添加多个元素。
+ public void Add(IEnumerable items)
+ {
+ if (items == null) return;
+ foreach (var item in items) Add(item);
+ }
+
/// 清空所有元素。
public void Clear()
{
@@ -138,6 +164,9 @@ namespace Apewer
/// 克隆当前实例,生成新实例。
public ArrayBuilder Clone() => new ArrayBuilder(this);
+ /// 使用 Export 方法实现从 ArrayBuilder<T> 到 T[] 的隐式转换。
+ public static implicit operator T[](ArrayBuilder instance) => instance == null ? null : instance.Export();
+
}
}
diff --git a/Apewer/ClockUtility.cs b/Apewer/ClockUtility.cs
index 90fc928..ce2d3d1 100644
--- a/Apewer/ClockUtility.cs
+++ b/Apewer/ClockUtility.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Globalization;
using System.Text;
namespace Apewer
@@ -104,7 +105,7 @@ namespace Apewer
/// 从毫秒时间戳获取 DateTime 对象。发生异常且不允许异常时将返回 1970-01-01 00:00:00.000。
///
- public static DateTime FromStamp(long stamp, bool exceptable = true)
+ public static DateTime FromStamp(long stamp, bool throwException = true)
{
try
{
@@ -113,13 +114,47 @@ namespace Apewer
}
catch
{
- if (exceptable) throw new ArgumentOutOfRangeException();
+ if (throwException) throw new ArgumentOutOfRangeException();
return Origin;
}
}
#endregion
+ #region Text
+
+ /// 解析文本,获取 DateTime 对象。
+ public static Class FromText(string text)
+ {
+ var str = text;
+ if (string.IsNullOrEmpty(str)) return null;
+
+ var utc = false;
+ var lower = str.ToLower();
+ if (lower.EndsWith(" utc"))
+ {
+ utc = true;
+ str = str.Substring(0, str.Length - 4);
+ }
+
+ DateTime dt;
+ if (!DateTime.TryParse(str, out dt))
+ {
+ if (!str.Contains("-") && DateTime.TryParseExact(str, "yyyy-M-d", null, DateTimeStyles.None, out dt))
+ {
+ if (!str.Contains("/") && DateTime.TryParseExact(str, "yyyy/M/d", null, DateTimeStyles.None, out dt))
+ {
+ return null;
+ }
+ }
+ }
+
+ if (utc) dt = new DateTime(dt.Ticks, DateTimeKind.Utc);
+ return new Class(dt);
+ }
+
+ #endregion
+
#region Lucid & Compact
/// 表示当前本地时间的文本,显示为易于阅读的格式。
diff --git a/Apewer/Json.cs b/Apewer/Json.cs
index 537d69d..96de6a5 100644
--- a/Apewer/Json.cs
+++ b/Apewer/Json.cs
@@ -276,32 +276,32 @@ namespace Apewer
#region Private Get
- private List PrivateGetProperties { get { return GetProperties(); } }
+ private Json[] PrivateGetProperties { get { return GetProperties(); } }
- private List PrivateGetValues { get { return GetValues(); } }
+ private Json[] PrivateGetValues { get { return GetValues(); } }
- private List PrivateGetObjects { get { return GetObjects(); } }
+ private Json[] PrivateGetObjects { get { return GetObjects(); } }
- private List PrivateGetItems { get { return GetItems(); } }
+ private Json[] PrivateGetItems { get { return GetItems(); } }
#endregion
#region Object : Get/Set
/// 获取所有类型为 Property 的子项。
- public List GetProperties()
+ public Json[] GetProperties()
{
- var list = new List();
+ var ab = new ArrayBuilder();
if (_jobject != null)
{
var children = _jobject.Children();
foreach (var child in children)
{
var json = new Json(child);
- list.Add(json);
+ ab.Add(json);
}
}
- return list;
+ return ab.Export();
}
/// 当前实例类型为 Object 时搜索属性,失败时返回 Null。
@@ -690,51 +690,51 @@ namespace Apewer
#region Array
/// 获取所有类型为 Value 的子项。
- public List GetValues()
+ public Json[] GetValues()
{
- var list = new List();
+ var ab = new ArrayBuilder();
if (_jarray != null)
{
var children = _jarray.Children();
foreach (var child in children)
{
var json = new Json(child);
- list.Add(json);
+ ab.Add(json);
}
}
- return list;
+ return ab.Export();
}
/// 获取所有类型为 Object 的子项。
- public List GetObjects()
+ public Json[] GetObjects()
{
- var list = new List();
+ var ab = new ArrayBuilder();
if (_jarray != null)
{
var children = _jarray.Children();
foreach (var child in children)
{
var json = new Json(child);
- list.Add(json);
+ ab.Add(json);
}
}
- return list;
+ return ab.Export();
}
/// 获取 Array 中的所有元素。
- public List GetItems()
+ public Json[] GetItems()
{
- var list = new List();
+ var ab = new ArrayBuilder();
if (_jarray != null)
{
var children = _jarray.Children();
foreach (var child in children)
{
var json = new Json(child);
- list.Add(json);
+ ab.Add(json);
}
}
- return list;
+ return ab.Export();
}
/// 当前实例类型为 Array 时添加 Null 元素。
@@ -1116,8 +1116,7 @@ namespace Apewer
public static Json From(IList entity, bool lower = false, int depth = -1, bool force = false)
{
if (entity == null) return null;
- var recursive = new List