diff --git a/Apewer.Source/Source/DbClient.cs b/Apewer.Source/Source/DbClient.cs
index ef95aa4..e54d61f 100644
--- a/Apewer.Source/Source/DbClient.cs
+++ b/Apewer.Source/Source/DbClient.cs
@@ -338,36 +338,6 @@ namespace Apewer.Source
#region static
- /// 对文本转义,符合 SQL 安全性。可根据字段类型限制 UTF-8 字节数,默认为 0 时不限制字节数。
- public 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;
- }
-
/// 获取表名。
protected static string Table() => Table(typeof(T));
diff --git a/Apewer.Source/Source/SqlClient.cs b/Apewer.Source/Source/SqlClient.cs
index 264560c..5c51830 100644
--- a/Apewer.Source/Source/SqlClient.cs
+++ b/Apewer.Source/Source/SqlClient.cs
@@ -1,4 +1,4 @@
-/* 2021.11.07 */
+/* 2021.12.01 */
using Apewer;
using System;
@@ -9,6 +9,7 @@ using System.Text;
using static Apewer.Source.SourceUtility;
using System.Data.SqlClient;
+using System.IO;
#if NETFRAMEWORK
using System.Data.Sql;
@@ -113,6 +114,24 @@ namespace Apewer.Source
}
}
+ /// 改变
+ ///
+ ///
+ public string Change(string store)
+ {
+ if (store.IsEmpty()) return "未指定数据名称。";
+
+ var connect = Connect();
+ if (connect.NotEmpty()) return connect;
+
+ try
+ {
+ _db.ChangeDatabase(store);
+ return null;
+ }
+ catch (Exception ex) { return ex.Message(); }
+ }
+
/// 关闭连接,并释放对象所占用的系统资源。
public void Close()
{
@@ -249,10 +268,13 @@ namespace Apewer.Source
}
/// 执行。
- public IExecute Execute(string sql) => Execute(sql, null);
+ public IExecute Execute(string sql) => Execute(sql, null, true);
+
+ /// 执行单条 Transact-SQL 语句,并加入参数。
+ public IExecute Execute(string sql, IEnumerable parameters) => Execute(sql, parameters, true);
/// 执行单条 Transact-SQL 语句,并加入参数。
- public IExecute Execute(string sql, IEnumerable parameters)
+ IExecute Execute(string sql, IEnumerable parameters, bool requireTransaction)
{
if (TextUtility.IsBlank(sql)) return Example.InvalidExecuteStatement;
@@ -260,13 +282,13 @@ namespace Apewer.Source
if (connected.NotEmpty()) return new Execute(false, connected);
var inTransaction = _transaction != null;
- if (!inTransaction) Begin();
+ if (requireTransaction && !inTransaction) Begin();
try
{
using (var command = new SqlCommand())
{
command.Connection = _db;
- command.Transaction = (SqlTransaction)_transaction;
+ if (requireTransaction) command.Transaction = (SqlTransaction)_transaction;
command.CommandTimeout = _timeout.Execute;
command.CommandText = sql;
if (parameters != null)
@@ -277,14 +299,14 @@ namespace Apewer.Source
}
}
var rows = command.ExecuteNonQuery();
- if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
+ if (requireTransaction && !inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
return new Execute(true, rows);
}
}
catch (Exception exception)
{
Logger.Error(nameof(SqlClient), "Execute", exception, sql);
- if (!inTransaction) Rollback();
+ if (requireTransaction && !inTransaction) Rollback();
return new Execute(exception);
}
}
@@ -355,6 +377,62 @@ namespace Apewer.Source
return list.ToArray();
}
+ /// 创建数据库,返回错误信息。
+ /// 数据库名称。
+ /// 成功时候返回 NULL 值,失败时返回错误信息。
+ public string CreateStore(string storeName)
+ {
+ var store = storeName.Escape().ToTrim();
+ if (store.IsEmpty()) return "创建失败:未指定数据库名称。";
+ if (ConnectionString.IsEmpty()) return "创建失败:未指定数据库连接方式。";
+
+ using (var source = new SqlClient(ConnectionString))
+ {
+ var connect = source.Connect();
+ if (connect.NotEmpty()) return "创建失败:" + connect;
+
+ var schema = source.SimpleCell("select default_schema_name from sys.database_principals where type = 'S' and name=user_name()");
+ if (schema.IsEmpty()) return "创建失败:无法获取默认模式名称。";
+
+ var refPath = source.SimpleCell(@"select f.physical_name path from sys.filegroups g left join sys.database_files f on f.data_space_id = g.data_space_id where g.name = 'PRIMARY' and g.type = 'FG' and g.is_default = 1 and g.filegroup_guid is null");
+ if (refPath.IsEmpty()) return "创建失败:无法获取文件路径。";
+
+ var dir = Path.GetDirectoryName(refPath);
+ var mdfPath = Path.Combine(dir, store) + ".mdf";
+ var ldfPath = Path.Combine(dir, store) + "_log.ldf";
+
+ // 创建库。
+ var sql1 = $@"
+CREATE DATABASE [{store}]
+ON PRIMARY
+(
+ NAME = N'{store}',
+ FILENAME = N'{mdfPath}',
+ SIZE = 8192KB,
+ MAXSIZE = UNLIMITED,
+ FILEGROWTH = 4MB
+)
+LOG ON
+(
+ NAME = N'{store}_log',
+ FILENAME = N'{ldfPath}',
+ SIZE = 8MB,
+ MAXSIZE = 1024MB,
+ FILEGROWTH = 4MB
+)
+COLLATE Chinese_PRC_CI_AS
+";
+ var create = source.Execute(sql1, null, false);
+ if (!create.Success) return TextUtility.Merge("创建失败:", create.Message);
+
+ // 设计兼容性级别。
+ var sql2 = $"ALTER DATABASE [{store}] SET COMPATIBILITY_LEVEL = 0";
+ source.Execute(sql2, null, false);
+
+ return null;
+ }
+ }
+
static string XType(int xtype)
{
switch (xtype)
diff --git a/Apewer/Apewer.props b/Apewer/Apewer.props
index 898879a..fed2cd8 100644
--- a/Apewer/Apewer.props
+++ b/Apewer/Apewer.props
@@ -9,7 +9,7 @@
Apewer
Apewer Libraries
- 6.5.7
+ 6.5.8
diff --git a/Apewer/NetworkUtility.cs b/Apewer/NetworkUtility.cs
index 196926d..cfa990e 100644
--- a/Apewer/NetworkUtility.cs
+++ b/Apewer/NetworkUtility.cs
@@ -383,7 +383,7 @@ namespace Apewer
#region Port
- private static int[] ListActivePort(IPEndPoint[] endpoints)
+ private static int[] ActivePorts(IPEndPoint[] endpoints)
{
var list = new List(endpoints.Length);
foreach (var endpoint in endpoints)
@@ -398,10 +398,10 @@ namespace Apewer
}
/// 列出活动的 TCP 端口。
- public static int[] ListActiveTcpPort() => ListActivePort(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
+ public static int[] ActiveTcpPorts() => ActivePorts(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
/// 列出活动的 UDP 端口。
- public static int[] ListActiveUdpPort() => ListActivePort(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
+ public static int[] ActiveUdpPorts() => ActivePorts(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
#endregion
diff --git a/Apewer/Source/Query.cs b/Apewer/Source/Query.cs
index 6a35933..ba37ecf 100644
--- a/Apewer/Source/Query.cs
+++ b/Apewer/Source/Query.cs
@@ -303,42 +303,6 @@ namespace Apewer.Source
private static T TextFormatter(object input) => (T)(Text(input) as object);
private static ObjectDisposedException DisposedException { get { return new ObjectDisposedException(typeof(Query).FullName); } }
-
- /// 简单查询:取结果中第 0 列所有单元格的文本形式,可指定查询后关闭服务器连接,返回结果中不包含无效文本。
- public static string[] SimpleColumn(IDbAdo database, string statement, bool dispose = false)
- {
- if (database == null) return new string[0];
- var ab = new ArrayBuilder();
- using (var query = database.Query(statement))
- {
- var rows = query.Rows;
- if (rows > 0)
- {
- var added = 0;
- for (int i = 0; i < rows; i++)
- {
- var cell = Trim(query.Text(i));
- if (string.IsNullOrEmpty(cell)) continue;
- ab.Add(cell);
- added++;
- }
- }
- }
- if (dispose) RuntimeUtility.Dispose(database);
- return ab.Export();
- }
-
- /// 简单查询:取结果中第 0 行、第 0 列单元格中的文本,可指定查询后关闭服务器连接。
- public static string SimpleCell(IDbAdo database, string statement, bool dispose = false)
- {
- if (database == null) return "";
- var query = database.Query(statement);
- var cell = Trim(Query.Text(query.Value()));
- query.Dispose();
- if (dispose) RuntimeUtility.Dispose(database);
- return cell;
- }
-
#endregion
#region Extension
diff --git a/Apewer/Source/SourceUtility.cs b/Apewer/Source/SourceUtility.cs
index dcbb987..29ec5bf 100644
--- a/Apewer/Source/SourceUtility.cs
+++ b/Apewer/Source/SourceUtility.cs
@@ -436,6 +436,84 @@ namespace Apewer.Source
#endregion
+ #region DbClient
+
+ /// 简单查询:取结果中第 0 列所有单元格的文本形式,可指定查询后关闭服务器连接,返回结果中不包含无效文本。
+ /// 数据库客户端。
+ /// 用于查询的 SQL 语句。
+ /// 查询后,关闭数据库链接。
+ public static string[] SimpleColumn(this IDbAdo source, string sql, bool close = false)
+ {
+ if (source == null) return new string[0];
+ var ab = new ArrayBuilder();
+ using (var query = source.Query(sql))
+ {
+ var rows = query.Rows;
+ if (rows > 0)
+ {
+ var added = 0;
+ for (int i = 0; i < rows; i++)
+ {
+ var cell = TextUtility.Trim(query.Text(i));
+ if (string.IsNullOrEmpty(cell)) continue;
+ ab.Add(cell);
+ added++;
+ }
+ }
+ }
+ if (close) RuntimeUtility.Dispose(source);
+ return ab.Export();
+ }
+
+ /// 简单查询:取结果中第 0 行、第 0 列单元格中的文本,可指定查询后关闭服务器连接。
+ /// 数据库客户端。
+ /// 用于查询的 SQL 语句。
+ /// 查询后,关闭数据库链接。
+ public static string SimpleCell(this IDbAdo source, string sql, bool close = false)
+ {
+ if (source == null) return null;
+ var value = null as string;
+ using (var query = source.Query(sql)) value = TextUtility.Trim(query.Text());
+ if (close) RuntimeUtility.Dispose(source);
+ return value;
+ }
+
+ #endregion
+
+ #region SQL
+
+ /// 对文本转义,符合 SQL 安全性。可根据字段类型限制 UTF-8 字节数,默认为 0 时不限制字节数。
+ public static string Escape(this 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
+
}
}
diff --git a/ChangeLog.md b/ChangeLog.md
index f507f94..d6d2d7a 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,6 +1,15 @@
### 最新提交
+### 6.5.8
+- Source:SqlClient 新增 CreateStore 方法,支持创建数据库。
+
+### 6.5.7
+- ArrayBuilder:增加 Contains 方法和 IndexOf 方法;
+- NetworkUtility:ListActivePort 返回值改为数组;
+- RuntimeUtility:StartThread 默认使用前台线程;
+- Source:OrmHelper 重命名为 SourceUtility。
+
### 6.5.6
- Global:增加 IsNull 和 NotNull 扩展方法;
- ArrayBuilder:添加了 Add 重载方法;