40 changed files with 1342 additions and 961 deletions
@ -0,0 +1,27 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Apewer.Source |
|||
{ |
|||
|
|||
/// <summary>列信息。</summary>
|
|||
[Serializable] |
|||
public sealed class ColumnInfo |
|||
{ |
|||
|
|||
/// <summary>字段。</summary>
|
|||
public string Name { get; set; } |
|||
|
|||
/// <summary>类型。</summary>
|
|||
public string Type { get; set; } |
|||
|
|||
/// <summary>长度。</summary>
|
|||
public int Length { get; set; } |
|||
|
|||
/// <summary>是主键。</summary>
|
|||
public int IsKey { get; set; } |
|||
|
|||
} |
|||
|
|||
} |
After Width: | Height: | Size: 17 KiB |
@ -1,32 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Apewer.Web |
|||
{ |
|||
|
|||
/// <summary>Cron 特性。</summary>
|
|||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] |
|||
public sealed class CronAttribute : Attribute |
|||
{ |
|||
|
|||
internal const int DefaultInterval = 60000; |
|||
|
|||
private int _internval; |
|||
|
|||
/// <summary>两次 Cron 执行的间隔毫秒数。</summary>
|
|||
public int Interval |
|||
{ |
|||
get { return _internval; } |
|||
private set { _internval = value < 1000 ? 1000 : value; } |
|||
} |
|||
|
|||
/// <summary>创建 Cron 特性,可指定两次 Cron 执行的间隔毫秒数。</summary>
|
|||
public CronAttribute(int interval = DefaultInterval) |
|||
{ |
|||
Interval = interval; |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
@ -1,124 +0,0 @@ |
|||
using Apewer; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using System.Threading; |
|||
|
|||
namespace Apewer.Web |
|||
{ |
|||
|
|||
internal sealed class CronInstance |
|||
{ |
|||
|
|||
private Thread _thread = null; |
|||
private Type _type = null; |
|||
private bool _break = false; |
|||
private bool _latest = false; |
|||
private CronAttribute _attribute = null; |
|||
private Nullable<DateTime> _ended = null; |
|||
|
|||
public CronInvoker Invoker { get; set; } |
|||
|
|||
public Thread Thread |
|||
{ |
|||
get { return _thread; } |
|||
} |
|||
|
|||
public bool Alive |
|||
{ |
|||
get { return GetAlive(); } |
|||
} |
|||
|
|||
/// <summary>再次启动 Cron 的时间间隔。</summary>
|
|||
public int Interval |
|||
{ |
|||
get { return GetInterval(); } |
|||
} |
|||
|
|||
/// <summary>最后一次检查的 Alive 值。</summary>
|
|||
public bool Latest |
|||
{ |
|||
get { return _latest; } |
|||
set { _latest = value; } |
|||
} |
|||
|
|||
public Type Type |
|||
{ |
|||
get { return _type; } |
|||
set { _type = value; } |
|||
} |
|||
|
|||
public bool Break |
|||
{ |
|||
get { return _break; } |
|||
set { _break = value; } |
|||
} |
|||
|
|||
public CronAttribute Attribute |
|||
{ |
|||
get { return _attribute; } |
|||
set { _attribute = value; } |
|||
} |
|||
|
|||
public Nullable<DateTime> Ended |
|||
{ |
|||
get { return _ended; } |
|||
set { _ended = value; } |
|||
} |
|||
|
|||
public CronInstance() |
|||
{ |
|||
_thread = new Thread(Listen); |
|||
_thread.IsBackground = true; |
|||
} |
|||
|
|||
void Log(params object[] content) => Invoker?.Log(content); |
|||
|
|||
public void Start() |
|||
{ |
|||
if (Alive) return; |
|||
_thread = new Thread(Listen); |
|||
_thread.IsBackground = true; |
|||
_thread.Start(); |
|||
} |
|||
|
|||
public void Abort() |
|||
{ |
|||
if (_thread != null) |
|||
{ |
|||
_thread.Abort(); |
|||
_thread = null; |
|||
} |
|||
} |
|||
|
|||
int GetInterval() |
|||
{ |
|||
if (Attribute != null) return Attribute.Interval; |
|||
return CronAttribute.DefaultInterval; |
|||
} |
|||
|
|||
bool GetAlive() |
|||
{ |
|||
if (_thread == null) return false; |
|||
if (_thread.IsAlive != true) return false; |
|||
if (Thread.ThreadState != ThreadState.Running) return false; |
|||
return true; |
|||
} |
|||
|
|||
void Listen() |
|||
{ |
|||
if (Type == null) return; |
|||
try |
|||
{ |
|||
Activator.CreateInstance(Type); |
|||
} |
|||
catch (Exception exception) |
|||
{ |
|||
Log(Type.FullName, exception.GetType().FullName, exception.Message); |
|||
} |
|||
_thread = null; |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,31 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using System.Text; |
|||
|
|||
namespace Apewer.Web |
|||
{ |
|||
|
|||
/// <summary>程序集资源。</summary>
|
|||
public static class Resources |
|||
{ |
|||
|
|||
static byte[] Bytes(string name) |
|||
{ |
|||
var assembly = Assembly.GetExecutingAssembly(); |
|||
using (var stream = assembly.GetManifestResourceStream(name)) return stream.Read(); |
|||
} |
|||
|
|||
static string Text(string name) => BytesUtility.WipeTextBom(Bytes(name)).Text(); |
|||
|
|||
/// <summary>获取预置的 favicon.ico 文件,。</summary>
|
|||
public static byte[] FavIcon() => Bytes("Apewer.FavIcon.ico"); |
|||
|
|||
/// <summary>获取用于 .NET Framework 4.0 的 web.config 文件。</summary>
|
|||
public static string WebConfig40() => Text("Apewer.WebConfig40.xml"); |
|||
|
|||
/// <summary>获取用于 .NET Framework 4.6.1 的 web.config 文件。</summary>
|
|||
public static string WebConfig461(bool netstandard = false) => Text(netstandard ? "Apewer.WebConfigStd.xml" : "Apewer.WebConfig461.xml"); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<configuration> |
|||
<system.web> |
|||
<compilation targetFramework="4.0" debug="true" /> |
|||
<customErrors mode="Off" /> |
|||
<globalization fileEncoding="utf-8" /> |
|||
<httpRuntime targetFramework="4.0" maxRequestLength="2147483647" executionTimeout="3600" enableVersionHeader="false" requestPathInvalidCharacters="" /> |
|||
<sessionState mode="Off" /> |
|||
<pages controlRenderingCompatibilityVersion="4.0" /> |
|||
</system.web> |
|||
<system.webServer> |
|||
<handlers> |
|||
<add name="HttpHandler" path="*" verb="*" type="Apewer.Web.ApiProgram" /> |
|||
</handlers> |
|||
<modules runAllManagedModulesForAllRequests="true"> |
|||
<add name="HttpModule" type="Apewer.Web.ApiProgram" /> |
|||
</modules> |
|||
<security> |
|||
<requestFiltering allowDoubleEscaping="true"> |
|||
<fileExtensions> |
|||
<clear /> |
|||
</fileExtensions> |
|||
<hiddenSegments> |
|||
<clear /> |
|||
</hiddenSegments> |
|||
<requestLimits maxAllowedContentLength="2147483647" /> |
|||
</requestFiltering> |
|||
</security> |
|||
</system.webServer> |
|||
</configuration> |
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<configuration> |
|||
<system.web> |
|||
<compilation targetFramework="4.6.1" debug="true" /> |
|||
<customErrors mode="Off" /> |
|||
<globalization fileEncoding="utf-8" /> |
|||
<httpRuntime targetFramework="4.0" maxRequestLength="2147483647" executionTimeout="3600" enableVersionHeader="false" requestPathInvalidCharacters="" /> |
|||
<sessionState mode="Off" /> |
|||
<pages controlRenderingCompatibilityVersion="4.0" /> |
|||
</system.web> |
|||
<system.webServer> |
|||
<handlers> |
|||
<add name="HttpHandler" path="*" verb="*" type="Apewer.Web.ApiProgram" /> |
|||
</handlers> |
|||
<modules runAllManagedModulesForAllRequests="true"> |
|||
<add name="HttpModule" type="Apewer.Web.ApiProgram" /> |
|||
</modules> |
|||
<security> |
|||
<requestFiltering allowDoubleEscaping="true"> |
|||
<fileExtensions> |
|||
<clear /> |
|||
</fileExtensions> |
|||
<hiddenSegments> |
|||
<clear /> |
|||
</hiddenSegments> |
|||
<requestLimits maxAllowedContentLength="2147483647" /> |
|||
</requestFiltering> |
|||
</security> |
|||
</system.webServer> |
|||
</configuration> |
@ -0,0 +1,34 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<configuration> |
|||
<system.web> |
|||
<compilation targetFramework="4.6.1" debug="true"> |
|||
<assemblies> |
|||
<add assembly="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" /> |
|||
</assemblies> |
|||
</compilation> |
|||
<customErrors mode="Off" /> |
|||
<globalization fileEncoding="utf-8" /> |
|||
<httpRuntime targetFramework="4.0" maxRequestLength="2147483647" executionTimeout="3600" enableVersionHeader="false" requestPathInvalidCharacters="" /> |
|||
<sessionState mode="Off" /> |
|||
<pages controlRenderingCompatibilityVersion="4.0" /> |
|||
</system.web> |
|||
<system.webServer> |
|||
<handlers> |
|||
<add name="HttpHandler" path="*" verb="*" type="Apewer.Web.ApiProgram" /> |
|||
</handlers> |
|||
<modules runAllManagedModulesForAllRequests="true"> |
|||
<add name="HttpModule" type="Apewer.Web.ApiProgram" /> |
|||
</modules> |
|||
<security> |
|||
<requestFiltering allowDoubleEscaping="true"> |
|||
<fileExtensions> |
|||
<clear /> |
|||
</fileExtensions> |
|||
<hiddenSegments> |
|||
<clear /> |
|||
</hiddenSegments> |
|||
<requestLimits maxAllowedContentLength="2147483647" /> |
|||
</requestFiltering> |
|||
</security> |
|||
</system.webServer> |
|||
</configuration> |
@ -0,0 +1,83 @@ |
|||
using Apewer.Web; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using System.Text; |
|||
|
|||
namespace Apewer |
|||
{ |
|||
|
|||
/// <summary>Cron 特性,默认间隔为 60000 毫秒。</summary>
|
|||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] |
|||
public sealed class CronAttribute : Attribute |
|||
{ |
|||
|
|||
internal const int DefaultInterval = 60000; |
|||
|
|||
private int _interval; |
|||
|
|||
/// <summary>两次 Cron 执行的间隔毫秒数。</summary>
|
|||
public int Interval |
|||
{ |
|||
get { return _interval; } |
|||
} |
|||
|
|||
/// <summary>创建 Cron 特性,可指定两次 Cron 执行的间隔毫秒数。</summary>
|
|||
public CronAttribute(int interval = DefaultInterval) |
|||
{ |
|||
_interval = interval; |
|||
} |
|||
|
|||
#region CronInvoker
|
|||
|
|||
private static Class<CronInvoker> _invoker = new Class<CronInvoker>(); |
|||
|
|||
/// <summary>开始 Cron 调用(不阻塞当前线程)。</summary>
|
|||
/// <remarks>
|
|||
/// 参数<br />
|
|||
/// - assemblies: 包含 Cron 的程序集,不指定此参数时将在 AppDomain 中搜索;<br />
|
|||
/// - logger: 日志记录程序,不指定此参数时将使用 Logger.Default。<br />
|
|||
/// </remarks>
|
|||
public static void Start(IEnumerable<Assembly> assemblies = null, Logger logger = null) |
|||
{ |
|||
CronInvoker instance = null; |
|||
lock (_invoker) |
|||
{ |
|||
if (_invoker) return; |
|||
instance = new CronInvoker(); |
|||
_invoker.Value = instance; |
|||
} |
|||
instance.Logger = logger ?? Logger.Default; |
|||
instance.Load(assemblies ?? AppDomain.CurrentDomain.GetAssemblies()); |
|||
|
|||
Console.CancelKeyPress += (s, e) => |
|||
{ |
|||
Break(); |
|||
e.Cancel = true; |
|||
}; |
|||
instance.Start(); |
|||
} |
|||
|
|||
/// <summary>在当前线程开始 Cron 调用(阻塞当前线程)。</summary>
|
|||
/// <remarks>
|
|||
/// 参数<br />
|
|||
/// - assemblies: 包含 Cron 的程序集,不指定此参数时将在 AppDomain 中搜索;<br />
|
|||
/// - logger: 日志记录程序,不指定此参数时将使用 Logger.Default。<br />
|
|||
/// </remarks>
|
|||
public static void Start(Logger logger, IEnumerable<Assembly> assemblies = null) => Start(assemblies, logger); |
|||
|
|||
/// <summary>打断 Cron 循环,不打断正在执行的 Cron。</summary>
|
|||
public static void Break() |
|||
{ |
|||
lock (_invoker) |
|||
{ |
|||
if (!_invoker) return; |
|||
_invoker.Value.Break(); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,95 @@ |
|||
using Apewer; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using System.Threading; |
|||
|
|||
namespace Apewer.Web |
|||
{ |
|||
|
|||
internal sealed class CronInstance |
|||
{ |
|||
|
|||
internal bool _latest = false; |
|||
internal Type _type = null; |
|||
internal Logger _logger = null; |
|||
internal Class<DateTime> _ended = null; |
|||
internal CronAttribute _attribute = null; |
|||
internal CronInvoker _invoker = null; |
|||
|
|||
private Thread _thread = null; |
|||
private bool _break = false; |
|||
|
|||
#region properties
|
|||
|
|||
// 当前线程正在运行。
|
|||
public bool Alive { get => GetAlive(); } |
|||
|
|||
// 再次启动 Cron 的时间间隔。
|
|||
public int Interval { get => GetInterval(); } |
|||
|
|||
// 最后一次检查的 Alive 值。
|
|||
public bool Latest { get => _latest; } |
|||
|
|||
// Cron 类型。
|
|||
public Type Type { get => _type; } |
|||
|
|||
public CronAttribute Attribute { get => _attribute; } |
|||
|
|||
public Class<DateTime> Ended { get => _ended; } |
|||
|
|||
#endregion
|
|||
|
|||
public CronInstance() |
|||
{ |
|||
_thread = new Thread(Listen); |
|||
_thread.IsBackground = true; |
|||
} |
|||
|
|||
/// <summary>打断循环。</summary>
|
|||
public void Break() => _break = true; |
|||
|
|||
/// <summary>启动线程执行任务。</summary>
|
|||
public void Start() |
|||
{ |
|||
if (Alive) return; |
|||
_thread = new Thread(Listen); |
|||
_thread.IsBackground = true; |
|||
_thread.Start(); |
|||
} |
|||
|
|||
int GetInterval() |
|||
{ |
|||
if (_attribute == null) _attribute = new CronAttribute(); |
|||
return _attribute.Interval; |
|||
} |
|||
|
|||
bool GetAlive() |
|||
{ |
|||
if (_thread == null) return false; |
|||
if (_thread.IsAlive != true) return false; |
|||
if (_thread.ThreadState != ThreadState.Running) return false; |
|||
return true; |
|||
} |
|||
|
|||
void Listen() |
|||
{ |
|||
if (Type == null) return; |
|||
var instance = null as object; |
|||
try |
|||
{ |
|||
instance = Activator.CreateInstance(Type); |
|||
} |
|||
catch (Exception exception) |
|||
{ |
|||
Log(Type.FullName, exception.GetType().FullName, exception.Message); |
|||
} |
|||
RuntimeUtility.Dispose(instance); |
|||
_thread = null; |
|||
} |
|||
|
|||
void Log(params object[] content) => _logger.Text(Type.FullName, content); |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,339 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Data; |
|||
using System.Data.Common; |
|||
using System.Text; |
|||
|
|||
namespace Apewer.Source |
|||
{ |
|||
|
|||
/// <summary></summary>
|
|||
abstract class DbClient |
|||
{ |
|||
|
|||
/// <summary></summary>
|
|||
public virtual Logger Logger { get; set; } |
|||
|
|||
#region Connection
|
|||
|
|||
DbConnection _conn = null; |
|||
string _str = null; |
|||
|
|||
/// <summary></summary>
|
|||
public Timeout Timeout { get; set; } |
|||
|
|||
/// <summary></summary>
|
|||
public DbConnection Connection { get => _conn; } |
|||
|
|||
/// <summary></summary>
|
|||
public bool Online { get => _conn == null ? false : (_conn.State == ConnectionState.Open); } |
|||
|
|||
/// <summary>连接字符串。</summary>
|
|||
public string ConnectionString { get => _str; } |
|||
|
|||
/// <summary></summary>
|
|||
public virtual string Connect() |
|||
{ |
|||
if (_conn == null) |
|||
{ |
|||
_str = GetConnectionString(); |
|||
_conn = NewConnection(); |
|||
_conn.ConnectionString = _str; |
|||
} |
|||
else |
|||
{ |
|||
if (_conn.State == ConnectionState.Open) return null; |
|||
} |
|||
|
|||
try |
|||
{ |
|||
_conn.Open(); |
|||
switch (_conn.State) |
|||
{ |
|||
case ConnectionState.Open: return null; |
|||
default: return $"连接失败,当前处于 {_conn.State} 状态。"; |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.Error(this, "Connect", ex, _conn.ConnectionString); |
|||
Close(); |
|||
return ex.Message; |
|||
} |
|||
} |
|||
|
|||
/// <summary></summary>
|
|||
public void Close() |
|||
{ |
|||
if (_conn != null) |
|||
{ |
|||
if (_transaction != null) |
|||
{ |
|||
if (_autocommit) Commit(); |
|||
else Rollback(); |
|||
} |
|||
_conn.Close(); |
|||
_conn.Dispose(); |
|||
_conn = null; |
|||
} |
|||
} |
|||
|
|||
/// <summary></summary>
|
|||
public void Dispose() { Close(); } |
|||
|
|||
#endregion
|
|||
|
|||
#region Transaction
|
|||
|
|||
private DbTransaction _transaction = null; |
|||
private bool _autocommit = false; |
|||
|
|||
/// <summary>启动事务。</summary>
|
|||
public string Begin(bool commit = true) => Begin(commit, null); |
|||
|
|||
/// <summary>启动事务。</summary>
|
|||
public string Begin(bool commit, Class<System.Data.IsolationLevel> isolation) |
|||
{ |
|||
if (Connect() != null) return "未连接。"; |
|||
if (_transaction != null) return "存在已启动的事务,无法再次启动。"; |
|||
try |
|||
{ |
|||
_transaction = isolation ? _conn.BeginTransaction(isolation.Value) : _conn.BeginTransaction(); |
|||
_autocommit = commit; |
|||
return null; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.Error(this, "Commit", ex.Message()); |
|||
return ex.Message(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>提交事务。</summary>
|
|||
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(this, "Commit", ex.Message()); |
|||
return ex.Message(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>从挂起状态回滚事务。</summary>
|
|||
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(this, "Rollback", ex.Message()); |
|||
return ex.Message(); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ADO
|
|||
|
|||
/// <summary>查询。</summary>
|
|||
public IQuery Query(string sql) => Query(sql, null); |
|||
|
|||
/// <summary>查询。</summary>
|
|||
public IQuery Query(string sql, IEnumerable<IDataParameter> parameters) |
|||
{ |
|||
if (TextUtility.IsBlank(sql)) return new Query(false, "语句无效。"); |
|||
var connected = Connect(); |
|||
if (connected.NotEmpty()) return new Query(false, connected); |
|||
|
|||
try |
|||
{ |
|||
using (var command = NewCommand()) |
|||
{ |
|||
command.Connection = _conn; |
|||
if (Timeout != null) command.CommandTimeout = Timeout.Query; |
|||
command.CommandText = sql; |
|||
if (parameters != null) |
|||
{ |
|||
foreach (var parameter in parameters) |
|||
{ |
|||
if (parameter != null) command.Parameters.Add(parameter); |
|||
} |
|||
} |
|||
using (var ds = new DataSet()) |
|||
{ |
|||
using (var da = NewDataAdapter(sql)) |
|||
{ |
|||
const string name = "result"; |
|||
da.Fill(ds, name); |
|||
var table = ds.Tables[name]; |
|||
return new Query(table, true); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
catch (Exception exception) |
|||
{ |
|||
Logger.Error(this, "Query", exception, sql); |
|||
return new Query(exception); |
|||
} |
|||
} |
|||
|
|||
/// <summary>执行。</summary>
|
|||
public IExecute Execute(string sql) => Execute(sql, null); |
|||
|
|||
/// <summary>执行单条 Transact-SQL 语句,并加入参数。</summary>
|
|||
public IExecute Execute(string sql, IEnumerable<IDataParameter> parameters) |
|||
{ |
|||
if (TextUtility.IsBlank(sql)) return Example.InvalidExecuteStatement; |
|||
|
|||
var connected = Connect(); |
|||
if (connected.NotEmpty()) return new Execute(false, connected); |
|||
|
|||
var inTransaction = _transaction != null; |
|||
if (!inTransaction) Begin(); |
|||
try |
|||
{ |
|||
using (var command = NewCommand()) |
|||
{ |
|||
command.Connection = _conn; |
|||
command.Transaction = (DbTransaction)_transaction; |
|||
if (Timeout != null) command.CommandTimeout = Timeout.Execute; |
|||
command.CommandText = sql; |
|||
if (parameters != null) |
|||
{ |
|||
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); |
|||
} |
|||
} |
|||
catch (Exception exception) |
|||
{ |
|||
Logger.Error(this, "Execute", exception, sql); |
|||
if (!inTransaction) Rollback(); |
|||
return new Execute(exception); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ORM - Query
|
|||
|
|||
/// <summary>查询记录。</summary>
|
|||
/// <param name="model">记录模型。</param>
|
|||
/// <param name="sql">SQL 语句。</param>
|
|||
public Result<object[]> Query(Type model, string sql) |
|||
{ |
|||
if (_conn == null) return new Result<object[]>("连接无效。"); |
|||
if (model == null) return new Result<object[]>("数据模型类型无效。"); |
|||
if (string.IsNullOrEmpty(sql)) return new Result<object[]>("SQL 语句无效。"); |
|||
|
|||
var query = Query(sql); |
|||
var result = null as Result<object[]>; |
|||
|
|||
if (query.Success) |
|||
{ |
|||
try |
|||
{ |
|||
var array = OrmHelper.Fill(query, model); |
|||
result = new Result<object[]>(array); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
result = new Result<object[]>(ex); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
result = new Result<object[]>(query.Message); |
|||
} |
|||
|
|||
query.Dispose(); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary></summary>
|
|||
public Result<T[]> Query<T>(string sql) where T : class, new() |
|||
{ |
|||
var query = Query(sql); |
|||
if (!query.Success) return new Result<T[]>(query.Message); |
|||
var records = query.Fill<T>(); |
|||
query.Dispose(); |
|||
|
|||
var result = new Result<T[]>(records); |
|||
return result; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Static
|
|||
|
|||
/// <summary>对文本转义,符合 SQL 安全性。可根据字段类型限制 UTF-8 字节数,默认为 0 时不限制字节数。</summary>
|
|||
protected static string Escape(string text, int bytes = 0) |
|||
{ |
|||
if (text.IsEmpty()) return ""; |
|||
|
|||
var t = text ?? ""; |
|||
t = t.Replace("\\", "\\\\"); |
|||
t = t.Replace("'", "\\'"); |
|||
t = t.Replace("\n", "\\n"); |
|||
t = t.Replace("\r", "\\r"); |
|||
t = t.Replace("\b", "\\b"); |
|||
t = t.Replace("\t", "\\t"); |
|||
t = t.Replace("\f", "\\f"); |
|||
|
|||
if (bytes > 5) |
|||
{ |
|||
if (t.Bytes(Encoding.UTF8).Length > bytes) |
|||
{ |
|||
while (true) |
|||
{ |
|||
t = t.Substring(0, t.Length - 1); |
|||
if (t.Bytes(Encoding.UTF8).Length <= (bytes - 4)) break; |
|||
} |
|||
t = t + " ..."; |
|||
} |
|||
} |
|||
|
|||
return t; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
/// <summary></summary>
|
|||
protected abstract string GetConnectionString(); |
|||
|
|||
/// <summary></summary>
|
|||
protected abstract DbConnection NewConnection(); |
|||
|
|||
/// <summary></summary>
|
|||
protected abstract DbDataAdapter NewDataAdapter(string sql); |
|||
|
|||
/// <summary></summary>
|
|||
protected abstract DbCommand NewCommand(); |
|||
|
|||
} |
|||
|
|||
} |
Loading…
Reference in new issue