diff --git a/Apewer.Source/Source/Access.cs b/Apewer.Source/Source/Access.cs
index 8857cd5..0eb8674 100644
--- a/Apewer.Source/Source/Access.cs
+++ b/Apewer.Source/Source/Access.cs
@@ -7,6 +7,7 @@ using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Text;
+using static Apewer.Source.SourceUtility;
#endif
namespace Apewer.Source
@@ -24,261 +25,335 @@ namespace Apewer.Source
#if NETFRAMEWORK
- public partial class Access : IDbAdo
+ public partial class Access : DbClient
{
#region 连接
string _connstr = null;
- OleDbConnection _connection = null;
- Timeout _timeout = null;
-
- /// 获取或设置日志记录。
- public Logger Logger { get; set; }
-
- /// 获取或设置超时。
- public Timeout Timeout { get => _timeout; }
/// 构造函数。
- public Access(string connectrionString, Timeout timeout)
+ public Access(string connectrionString, Timeout timeout = null) : base(timeout)
{
_connstr = connectrionString;
- _timeout = timeout ?? Timeout.Default;
}
- #endregion
-
- #region 连接
-
- /// 获取当前的 OldDbConnection 对象。
- public IDbConnection Connection { get => _connection; }
+ OleDbConnection OleDbConnection { get => (OleDbConnection)Connection; }
- /// 数据库是否已经连接。
- public bool Online
- {
- get
- {
- if (_connection != null)
- {
- if (_connection.State == ConnectionState.Open) return true;
- }
- return false;
- }
- }
+ #endregion
- /// 连接数据库,若未连接则尝试连接。
- /// 错误信息。
- public string Connect()
- {
- if (_connection == null)
- {
- _connection = new OleDbConnection();
- _connection.ConnectionString = _connstr;
- }
- else
- {
- if (_connection.State == ConnectionState.Open) return null;
- }
- try
- {
- _connection.Open();
- if (_connection.State == ConnectionState.Open) return null;
- }
- catch (Exception ex)
- {
- Logger.Error(nameof(Access), "Connect", ex, _connstr);
- Close();
- return ex.Message;
- }
- return "连接失败。";
- }
+ #region public
- /// 释放对象所占用的系统资源。
- public void Close()
+ ///
+ public override string[] ColumnNames(string tableName)
{
- if (_connection != null)
+ // OleDbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
+ var table = OleDbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, tableName.ToString(), null });
+ using (var query = new Query(table))
{
- if (_transaction != null)
+ var names = new ArrayBuilder();
+ for (var i = 0; i < query.Rows; i++)
{
- if (_autocommit) Commit();
- else Rollback();
+ names.Add(query.Text(i, "COLUMN_NAME"));
}
- _connection.Close();
- _connection.Dispose();
- _connection = null;
+ return names.Export();
}
}
- /// 释放资源。
- public void Dispose() => Close();
+ ///
+ public override string[] StoreNames() => throw new InvalidOperationException();
- #endregion
-
- #region Transaction
+ ///
+ public override string[] TableNames() => TextColumn("select name from msysobjects where type=1 and flags = 0");
- private IDbTransaction _transaction = null;
- private bool _autocommit = false;
+ ///
+ public override string Insert(object record, string table = null)
+ {
+ if (record == null) return "参数无效。";
+ FixProperties(record);
- /// 启动事务。
- public string Begin(bool commit = true) => Begin(commit, null);
+ var structure = TableStructure.Parse(record.GetType());
+ if (structure == null) return "无法解析记录模型。";
+ if (string.IsNullOrEmpty(table)) table = structure.Name;
+ if (string.IsNullOrEmpty(table)) return "表名称无效。";
- /// 启动事务。
- public string Begin(bool commit, Class isolation)
- {
- var connect = Connect();
- if (connect.NotEmpty()) return connect;
- if (_transaction != null) return "存在已启动的事务,无法再次启动。";
- try
- {
- _transaction = isolation ? _connection.BeginTransaction(isolation.Value) : _connection.BeginTransaction();
- _autocommit = commit;
- return null;
- }
- catch (Exception ex)
+ // 排除字段。
+ var excluded = new List();
+ foreach (var ca in structure.Columns)
{
- Logger.Error(nameof(Access), "Begin", ex.Message());
- return ex.Message();
+ // 排除不使用 ORM 的属性。
+ if (ca.Independent || ca.Incremental) excluded.Add(ca.Field);
}
- }
- /// 提交事务。
- public string Commit()
- {
- if (_transaction == null) return "事务不存在。";
- try
- {
- _transaction.Commit();
- RuntimeUtility.Dispose(_transaction);
- _transaction = null;
- return null;
- }
- catch (Exception ex)
+ var ps = structure.CreateParameters(record, Parameter, excluded);
+ var psc = ps.Length;
+ if (psc < 1) return "数据模型不包含字段。";
+
+ var names = new List(psc);
+ var values = new List(psc);
+ foreach (var column in ps)
{
- RuntimeUtility.Dispose(_transaction);
- _transaction = null;
- Logger.Error(nameof(Access), "Commit", ex.Message());
- return ex.Message();
+ //names.Add(TextGenerator.Merge("[", column, "]"));
+ names.Add(TextUtility.Merge(column));
+ values.Add("@" + column);
}
+ var sb = new StringBuilder();
+ sb.Append("insert into [", table, "](", string.Join(", ", names.ToArray()), ") ");
+ sb.Append("values(", string.Join(", ", values.ToArray()), "); ");
+ var sql = sb.ToString();
+
+ var execute = Execute(sql, ps);
+ if (execute.Success) return TextUtility.Empty;
+ return execute.Message;
}
- /// 从挂起状态回滚事务。
- public string Rollback()
+ ///
+ public override string Update(IRecord record, string table = null)
{
- if (_transaction == null) return "事务不存在。";
- try
+ if (record == null) return "参数无效。";
+ FixProperties(record);
+ SetUpdated(record);
+
+ var structure = TableStructure.Parse(record.GetType());
+ if (structure == null) return "无法解析记录模型。";
+ if (structure.Independent) return "无法更新带有 Independent 特性的模型。";
+ if (string.IsNullOrEmpty(table)) table = structure.Name;
+ if (string.IsNullOrEmpty(table)) return "表名称无效。";
+
+ // 排除字段。
+ var excluded = new List();
+ if (structure.Key != null) excluded.Add(structure.Key.Field);
+ foreach (var ca in structure.Columns)
{
- _transaction.Rollback();
- RuntimeUtility.Dispose(_transaction);
- _transaction = null;
- return null;
+ // 排除不使用 ORM 的属性、自增属性和主键属性。
+ if (ca.Independent || ca.Incremental || ca.PrimaryKey) excluded.Add(ca.Field);
}
- catch (Exception ex)
+
+ var ps = structure.CreateParameters(record, Parameter, excluded);
+ var psc = ps.Length;
+ if (psc < 1) return "数据模型不包含字段。";
+
+ var items = new List();
+ foreach (var p in ps)
{
- RuntimeUtility.Dispose(_transaction);
- _transaction = null;
- Logger.Error(nameof(Access), "Rollback", ex.Message);
- return ex.Message();
+ var pn = p.ParameterName;
+ items.Add(TextUtility.Merge("[", pn, "] = @", pn));
}
+ var key = record.Key.SafeKey();
+ var sql = $"update [{table}] set {string.Join(", ", items.ToArray())} where [{structure.Key.Field}]='{key}'";
+
+ var execute = Execute(sql, ps);
+ if (execute.Success) return TextUtility.Empty;
+ return execute.Message;
}
#endregion
- #region 查询和执行
+ #region protected
- /// 使用 SQL 语句进行查询。
- public IQuery Query(string sql) => Query(sql, null);
+ ///
+ protected override string NewConnectionString() => _connstr;
- /// 使用 SQL 语句进行查询。
- public IQuery Query(string sql, IEnumerable parameters)
- {
- if (sql.IsBlank()) return Example.InvalidQueryStatement;
+ ///
+ protected override IDbConnection CreateConnection() => new OleDbConnection();
- var connected = Connect();
- if (connected.NotEmpty()) return new Query(false, connected);
+ ///
+ protected override IDataAdapter CreateDataAdapter(IDbCommand command) => new OleDbDataAdapter((OleDbCommand)command);
- try
+ ///
+ protected override IDataParameter CreateParameter() => new OleDbParameter();
+
+ ///
+ protected override string Initialize(TableStructure structure)
+ {
+ var model = structure.Model;
+
+ // 检查现存表。
+ var exists = false;
+ var tables = TableNames();
+ if (tables.Length > 0)
{
- using (var command = new OleDbCommand())
+ var lower = structure.Name.ToLower();
+ foreach (var table in tables)
{
- command.Connection = _connection;
- command.CommandTimeout = Timeout.Query;
- command.CommandText = sql;
- if (parameters != null)
+ if (TextUtility.IsBlank(table)) continue;
+ if (table.ToLower() == lower)
{
- foreach (var p in parameters)
- {
- if (p != null) command.Parameters.Add(p);
- }
- }
- using (var ds = new DataSet())
- {
- using (var da = new OleDbDataAdapter(sql, _connection))
- {
- var name = "table_" + Guid.NewGuid().ToString("n");
- da.Fill(ds, name);
- var table = ds.Tables[name];
- return new Query(table);
- }
+ exists = true;
+ break;
}
}
}
- catch (Exception exception)
+
+ if (exists)
{
- Logger.Error(nameof(Access), "Query", exception, sql);
- return new Query(exception);
- }
- }
+ // 获取已存在的列名。
+ var columns = ColumnNames(structure.Name);
+ if (columns.Length > 0)
+ {
+ var lower = new List();
+ foreach (var column in columns)
+ {
+ if (TextUtility.IsBlank(column)) continue;
+ lower.Add(column.ToLower());
+ }
+ columns = lower.ToArray();
+ }
- /// 执行 SQL 语句。
- public IExecute Execute(string sql) => Execute(sql, null);
+ // 增加列。
+ foreach (var column in structure.Columns)
+ {
+ // 检查 Independent 特性。
+ if (structure.Independent && column.Independent) continue;
- /// 执行 SQL 语句,并加入参数。
- public IExecute Execute(string sql, IEnumerable parameters)
- {
- if (sql.IsBlank()) return Example.InvalidExecuteStatement;
+ // 去重。
+ var lower = column.Field.ToLower();
+ if (columns.Contains(lower)) continue;
- var connected = Connect();
- if (connected.NotEmpty()) return new Execute(false, connected);
+ var type = Declaration(column);
+ if (string.IsNullOrEmpty(type)) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
- var inTransaction = _transaction != null;
- if (!inTransaction) Begin();
- try
+ var sql = TextUtility.Merge("alter table [", structure.Name, "] add ", type, "; ");
+ var execute = Execute(sql);
+ if (execute.Success == false) return execute.Message;
+ }
+ return TextUtility.Empty;
+ }
+ else
{
- using (var command = new OleDbCommand())
+ var sqlcolumns = new List();
+ foreach (var column in structure.Columns)
{
- command.Connection = _connection;
- command.Transaction = (OleDbTransaction)_transaction;
- command.CommandTimeout = Timeout.Execute;
- command.CommandText = sql;
- if (parameters != null)
+ // 检查 Independent 特性。
+ if (structure.Independent && column.Independent) continue;
+
+ var type = Declaration(column);
+ if (!column.Independent)
{
- foreach (var parameter in parameters)
- {
- if (parameter == null) continue;
- command.Parameters.Add(parameter);
- }
+ if (column.PrimaryKey) type = type + " primary key";
+ if (column.Incremental) type += " identity";
}
- var rows = command.ExecuteNonQuery();
- if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
- return new Execute(true, rows);
+
+ if (string.IsNullOrEmpty(type)) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
+ sqlcolumns.Add(type);
}
+ if (sqlcolumns.Count < 1) return $"无法对类型 {model.FullName} 创建表:没有定义任何字段。";
+ var sql = TextUtility.Merge("create table [", structure.Name, "](", string.Join(", ", sqlcolumns.ToArray()), "); ");
+ var execute = Execute(sql);
+ if (execute.Success) return TextUtility.Empty;
+ return execute.Message;
}
- catch (Exception exception)
- {
- Logger.Error(nameof(Access), "Execute", exception, sql);
- if (!inTransaction) Rollback();
- return new Execute(exception);
- }
+
+ }
+
+ ///
+ protected override string KeysSql(string tableName, string keyField, string flagField, long flagValue)
+ {
+ if (flagValue == 0) return $"select [{keyField}] from [{tableName}]";
+ else return $"select [{keyField}] from [{tableName}] where [{flagField}] = {flagValue}";
+ }
+
+ ///
+ protected override string RecordSql(string tableName, string keyField, string keyValue, string flagField, long flagValue)
+ {
+ if (flagValue == 0) return $"select top 1 * from [{tableName}] where [{keyField}] = '{keyValue}'";
+ else return $"select top 1 * from [{tableName}] where [{keyField}] = '{keyValue}' and [{flagField}] = {flagValue}";
+ }
+
+ ///
+ protected override string RecordsSql(string tableName, string flagField, long flagValue)
+ {
+ if (flagValue == 0) return $"select * from [{tableName}]";
+ else return $"select * from [{tableName}] where [{flagField}] = {flagValue}";
}
#endregion
#region Parameter
- /// 创建参数列表。
- public static List NewParameterList()
+ /// 创建参数。
+ ///
+ ///
+ static OleDbParameter Parameter(Parameter parameter)
+ {
+ if (parameter == null) throw new InvalidOperationException("参数无效。");
+ return Parameter(parameter.Name, parameter.Type, parameter.Size, parameter.Value);
+ }
+
+ /// 创建参数。
+ public static OleDbParameter Parameter(string name, ColumnType type, int size, object value)
{
- return new List();
+ var vname = TextUtility.Trim(name);
+ if (TextUtility.IsBlank(vname)) return null;
+
+ var vtype = OleDbType.BigInt;
+ switch (type)
+ {
+ case ColumnType.Boolean:
+ vtype = OleDbType.Boolean;
+ break;
+ case ColumnType.Bytes:
+ vtype = OleDbType.LongVarBinary;
+ break;
+ case ColumnType.Integer:
+ vtype = OleDbType.Integer;
+ break;
+ case ColumnType.Float:
+ vtype = OleDbType.Double;
+ break;
+ case ColumnType.DateTime:
+ vtype = OleDbType.Date;
+ break;
+ case ColumnType.VarChar:
+ case ColumnType.VarChar191:
+ case ColumnType.VarCharMax:
+ vtype = OleDbType.VarChar;
+ break;
+ case ColumnType.NVarChar:
+ case ColumnType.NVarChar191:
+ case ColumnType.NVarCharMax:
+ vtype = OleDbType.VarWChar;
+ break;
+ case ColumnType.Text:
+ vtype = OleDbType.LongVarChar;
+ break;
+ case ColumnType.NText:
+ vtype = OleDbType.LongVarWChar;
+ break;
+ default:
+ throw new InvalidOperationException(TextUtility.Merge("类型 ", type.ToString(), " 不受支持。"));
+ }
+
+ var vsize = size;
+ switch (type)
+ {
+ case ColumnType.VarChar:
+ vsize = NumberUtility.Restrict(vsize, 0, 8000);
+ break;
+ case ColumnType.NVarChar:
+ vsize = NumberUtility.Restrict(vsize, 0, 4000);
+ break;
+ case ColumnType.VarChar191:
+ case ColumnType.NVarChar191:
+ vsize = NumberUtility.Restrict(vsize, 0, 191);
+ break;
+ default:
+ vsize = 0;
+ break;
+ }
+
+ var vvalue = value;
+ if (vvalue is string && vvalue != null && vsize > 0)
+ {
+ vvalue = TextUtility.Left((string)vvalue, vsize);
+ }
+
+ var parameter = new OleDbParameter();
+ parameter.ParameterName = vname;
+ parameter.OleDbType = vtype;
+ parameter.Value = vvalue;
+ if (vsize > 0) parameter.Size = vsize;
+ return parameter;
}
/// 创建参数。
@@ -328,6 +403,62 @@ namespace Apewer.Source
#endregion
+ #region static
+
+ static string Declaration(ColumnAttribute column)
+ {
+ var type = TextUtility.Empty;
+ var vcolumn = column;
+ var length = Math.Max(0, vcolumn.Length);
+ switch (vcolumn.Type)
+ {
+ case ColumnType.Boolean:
+ type = "bit";
+ break;
+ case ColumnType.Integer:
+ type = "money";
+ break;
+ case ColumnType.Float:
+ type = "float";
+ break;
+ case ColumnType.Bytes:
+ type = "binary";
+ 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(191)");
+ 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
+
}
/// 使用 Microsoft.Jet.OLEDB.4.0 访问 Access 97 - 2003 数据库文件。
diff --git a/Apewer.Source/Source/DbClient.cs b/Apewer.Source/Source/DbClient.cs
index e54d61f..ea0611a 100644
--- a/Apewer.Source/Source/DbClient.cs
+++ b/Apewer.Source/Source/DbClient.cs
@@ -1,17 +1,14 @@
-#if DEBUG
-
-using System;
+using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
+using System.Reflection;
using System.Text;
namespace Apewer.Source
{
/// 数据库客户端基类。
-
-
public abstract class DbClient : IDbClient
{
@@ -19,7 +16,10 @@ namespace Apewer.Source
public virtual Logger Logger { get; set; }
///
- public DbClient(Timeout timeout) { _timeout = timeout ?? Timeout.Default; }
+ internal DbClient(Timeout timeout)
+ {
+ _timeout = timeout ?? Timeout.Default;
+ }
#region connection
@@ -27,6 +27,9 @@ namespace Apewer.Source
IDbConnection _conn = null;
string _str = null;
+ ///
+ internal protected object Locker = new object();
+
///
public Timeout Timeout { get => _timeout; set => _timeout = value ?? Timeout.Default; }
@@ -44,15 +47,11 @@ namespace Apewer.Source
{
if (_conn == null)
{
- _str = NewConnectionString();
- _conn = NewConnection();
- _conn.ConnectionString = _str;
- }
- else
- {
- if (_conn.State == ConnectionState.Open) return null;
+ _conn = CreateConnection();
+ _conn.ConnectionString = NewConnectionString();
}
+ if (_conn.State == ConnectionState.Open) return null;
try
{
_conn.Open();
@@ -63,12 +62,32 @@ namespace Apewer.Source
}
catch (Exception ex)
{
- Logger.Error(this, "Connect", ex.GetType().Name, ex.Message, _str);
+ Logger.Error(this, "Connect", ex.Message, _str);
Close();
return ex.Message;
}
}
+ /// 更改已打开的数据库。
+ public string Change(string store)
+ {
+ if (store.IsEmpty()) return "未指定数据名称。";
+
+ var connect = Connect();
+ if (connect.NotEmpty()) return connect;
+
+ try
+ {
+ Connection.ChangeDatabase(store);
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(this, "Change", ex.Message, _str);
+ return ex.Message();
+ }
+ }
+
/// 关闭连接,并释放对象所占用的系统资源。
public void Close()
{
@@ -78,15 +97,18 @@ namespace Apewer.Source
{
if (_autocommit) Commit();
else Rollback();
+ _transaction = null;
}
- _conn.Close();
- _conn.Dispose();
- _conn = null;
+ try { _conn.Close(); } catch { }
}
}
/// 关闭连接,释放对象所占用的系统资源,并清除连接信息。
- public void Dispose() { Close(); }
+ public void Dispose()
+ {
+ Close();
+ RuntimeUtility.Dispose(_conn);
+ }
#endregion
@@ -95,19 +117,10 @@ namespace Apewer.Source
private IDbTransaction _transaction = null;
private bool _autocommit = false;
- ///
- /// 启动事务,可指定事务锁定行为。
- /// Chaos
无法覆盖隔离级别更高的事务中的挂起的更改。
- /// ReadCommitted
在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。
- /// ReadUncommitted
可以进行脏读,意思是说,不发布共享锁,也不接受独占锁。
- /// RepeatableRead
在查询中使用的所有数据上放置锁,以防止其他用户更新这些数据。 防止不可重复的读取,但是仍可以有幻像行。
- /// Serializable
在 System.Data.DataSet 上放置范围锁,以防止在事务完成之前由其他用户更新行或向数据集中插入行。
- /// Snapshot
通过在一个应用程序正在修改数据时存储另一个应用程序可以读取的相同数据版本来减少阻止。 表示您无法从一个事务中看到在其他事务中进行的更改,即便重新查询也是如此。
- /// Unspecified = -1
正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。
- ///
- /// 在连接的生命周期结束时未结束事务,指定 TRUE 将自动提交,指定 FALSE 将自动回滚。
- /// 指定事务锁定行为,不指定时将使用默认值。
- public string Begin(bool commit = false, Class isolation = null)
+ /// 获取已启动的事务。
+ public IDbTransaction Transaction { get => _transaction; }
+
+ string Begin(bool commit, Class isolation)
{
if (_transaction != null) return "已存在未完成的事务,无法再次启动。";
var connect = Connect();
@@ -125,6 +138,33 @@ namespace Apewer.Source
}
}
+ ///
+ /// 使用默认的事务锁定行为启动事务。
+ /// Chaos
无法覆盖隔离级别更高的事务中的挂起的更改。
+ /// ReadCommitted
在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。
+ /// ReadUncommitted
可以进行脏读,意思是说,不发布共享锁,也不接受独占锁。
+ /// RepeatableRead
在查询中使用的所有数据上放置锁,以防止其他用户更新这些数据。 防止不可重复的读取,但是仍可以有幻像行。
+ /// Serializable
在 System.Data.DataSet 上放置范围锁,以防止在事务完成之前由其他用户更新行或向数据集中插入行。
+ /// Snapshot
通过在一个应用程序正在修改数据时存储另一个应用程序可以读取的相同数据版本来减少阻止。 表示您无法从一个事务中看到在其他事务中进行的更改,即便重新查询也是如此。
+ /// Unspecified = -1
正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。
+ ///
+ /// 在连接的生命周期结束时未结束事务,指定 TRUE 将自动提交,指定 FALSE 将自动回滚。
+ public string Begin(bool commit = false) => Begin(commit, null);
+
+ ///
+ /// 使用指定的事务锁定行为启动事务。
+ /// Chaos
无法覆盖隔离级别更高的事务中的挂起的更改。
+ /// ReadCommitted
在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。
+ /// ReadUncommitted
可以进行脏读,意思是说,不发布共享锁,也不接受独占锁。
+ /// RepeatableRead
在查询中使用的所有数据上放置锁,以防止其他用户更新这些数据。 防止不可重复的读取,但是仍可以有幻像行。
+ /// Serializable
在 System.Data.DataSet 上放置范围锁,以防止在事务完成之前由其他用户更新行或向数据集中插入行。
+ /// Snapshot
通过在一个应用程序正在修改数据时存储另一个应用程序可以读取的相同数据版本来减少阻止。 表示您无法从一个事务中看到在其他事务中进行的更改,即便重新查询也是如此。
+ /// Unspecified = -1
正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。
+ ///
+ /// 在连接的生命周期结束时未结束事务,指定 TRUE 将自动提交,指定 FALSE 将自动回滚。
+ /// 指定事务锁定行为,不指定时将使用默认值。
+ public string Begin(bool commit, IsolationLevel isolation) => Begin(commit, new Class(isolation));
+
/// 提交事务。
public string Commit()
{
@@ -170,10 +210,7 @@ namespace Apewer.Source
#region ado
/// 查询。
- public IQuery Query(string sql) => Query(sql, null);
-
- /// 查询。
- public IQuery Query(string sql, IEnumerable parameters)
+ public IQuery Query(string sql, IEnumerable parameters = null)
{
if (TextUtility.IsEmpty(sql)) return new Query(false, "语句无效。");
@@ -182,7 +219,7 @@ namespace Apewer.Source
try
{
- using (var command = NewCommand())
+ using (var command = _conn.CreateCommand())
{
command.Connection = _conn;
if (_timeout != null) command.CommandTimeout = Timeout.Query;
@@ -194,82 +231,81 @@ namespace Apewer.Source
if (parameter != null) command.Parameters.Add(parameter);
}
}
-
var ex = null as Exception;
var da = null as IDataAdapter;
- try { da = NewDataAdapter(command); }
+ try { da = CreateDataAdapter(command); }
catch (Exception adapterEx) { ex = adapterEx; }
- if (ex == null)
+ if (ex != null)
{
- using (var ds = new DataSet())
- {
- da.Fill(ds);
- if (ds.Tables.Count > 0)
- {
- var tables = new DataTable[ds.Tables.Count];
- ds.Tables.CopyTo(tables, 0);
- return new Query(tables, true);
- }
- else
- {
- Logger.Error(this, "Query", "查询结果不包含任何数据表。", sql);
- return new Query(false, "查询结果不包含任何数据表。");
- }
- }
+ Logger.Error(this, "Query", ex.Message, sql);
+ return new Query(ex);
}
- else
+
+ using (var ds = new DataSet())
{
- Logger.Error(this, "Query", ex.GetType().FullName, ex.Message, sql);
- return new Query(ex);
+ da.Fill(ds);
+ if (ds.Tables.Count > 0)
+ {
+ var tables = new DataTable[ds.Tables.Count];
+ ds.Tables.CopyTo(tables, 0);
+ Logger.Info(this, "Query", sql);
+ return new Query(tables, true);
+ }
+ else
+ {
+ Logger.Error(this, "Query", "查询结果不包含任何数据表。", sql);
+ return new Query(false, "查询结果不包含任何数据表。");
+ }
}
}
}
catch (Exception exception)
{
- Logger.Error(this, "Query", exception.GetType().FullName, exception.Message, sql);
+ Logger.Error(this, "Query", exception.Message, sql);
return new Query(exception);
}
}
- /// 执行。
- public IExecute Execute(string sql) => Execute(sql, null);
-
- /// 执行单条 Transact-SQL 语句,并加入参数。
- public IExecute Execute(string sql, IEnumerable parameters)
+ /// 执行 SQL 语句,并加入参数。
+ public IExecute Execute(string sql, IEnumerable parameters = null, bool autoTransaction = true)
{
if (TextUtility.IsEmpty(sql)) return new Execute(false, "语句无效。");
- var connected = Connect();
- if (connected.NotEmpty()) return new Execute(false, connected);
-
- var inTransaction = _transaction != null;
- if (!inTransaction) Begin();
- try
+ lock (Locker)
{
+ var connected = Connect();
+ if (connected.NotEmpty()) return new Execute(false, connected);
- using (var command = NewCommand())
+ var inTransaction = _transaction != null;
+ if (autoTransaction && !inTransaction) Begin();
+ try
{
- command.Connection = _conn;
- command.Transaction = (DbTransaction)_transaction;
- if (Timeout != null) command.CommandTimeout = Timeout.Execute;
- command.CommandText = sql;
- if (parameters != null)
+
+ using (var command = _conn.CreateCommand())
{
- foreach (var parameter in parameters)
+ command.Connection = _conn;
+ if (autoTransaction) command.Transaction = (DbTransaction)_transaction;
+ if (Timeout != null) 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 (autoTransaction && !inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
+ Logger.Info(this, "Execute", sql);
+ return new Execute(true, rows);
}
- var rows = command.ExecuteNonQuery();
- if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
- return new Execute(true, rows);
}
- }
- catch (Exception exception)
- {
- Logger.Error(this, "Execute", exception, sql);
- if (!inTransaction) Rollback();
- return new Execute(exception);
+ catch (Exception exception)
+ {
+ Logger.Error(this, "Execute", exception.Message, sql);
+ if (autoTransaction && !inTransaction) Rollback();
+ return new Execute(exception);
+ }
}
}
@@ -294,12 +330,69 @@ namespace Apewer.Source
#endregion
+ #region parameter
+
+ /// 创建参数。
+ ///
+ public IDataParameter Parameter(string name, object value)
+ {
+ if (name.IsEmpty()) throw new ArgumentNullException(nameof(name));
+
+ var p = CreateParameter();
+ p.ParameterName = name;
+ p.Value = value;
+ return p;
+ }
+
+ /// 创建参数。
+ ///
+ public IDataParameter Parameter(string name, object value, DbType type)
+ {
+ if (name.IsEmpty()) throw new ArgumentNullException(nameof(name));
+
+ var p = CreateParameter();
+ p.ParameterName = name;
+ p.Value = value;
+ p.DbType = type;
+ return p;
+ }
+
+ #endregion
+
#region orm
- /// 使用指定语句查询,获取查询结果。
- /// 要执行的 SQL 语句。
- /// 为 SQL 语句提供的参数。
- public Result Query(string sql, IEnumerable parameters = null) where T : class, new() => SourceUtility.As