You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

943 lines
34 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #if NET40 || NET461
  2. /* 2021.08.03 */
  3. using Apewer;
  4. using Apewer.Source;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Data;
  8. using System.Data.Common;
  9. using System.Data.Sql;
  10. using System.Data.SqlClient;
  11. using System.Text;
  12. namespace Apewer.Source
  13. {
  14. /// <summary>用于快速连接 Microsoft SQL Server 数据库的辅助。</summary>
  15. [Serializable]
  16. public class SqlServer : IDatabase, IOrm, IDisposable
  17. {
  18. #region 变量定义。
  19. private SqlConnection _db = null;
  20. private Timeout _timeout;
  21. private string _connectionstring = "";
  22. private string _address = "";
  23. private string _store = "";
  24. private string _user = "";
  25. private string _pass = "";
  26. #endregion
  27. #region 构造函数。
  28. /// <summary>创建空参数的数据库连接实例。</summary>
  29. public SqlServer()
  30. {
  31. _timeout = Timeout.Default;
  32. }
  33. /// <summary>使用连接字符串创建数据库连接实例。</summary>
  34. public SqlServer(string connectionString)
  35. {
  36. _timeout = Timeout.Default;
  37. _connectionstring = connectionString ?? "";
  38. }
  39. /// <summary>使用连接凭据创建数据库连接实例。</summary>
  40. /// <param name="address">服务器地址。</param>
  41. /// <param name="store">数据库名称。</param>
  42. public SqlServer(string address, string store)
  43. {
  44. _timeout = Timeout.Default;
  45. _address = address ?? "";
  46. _store = store ?? "";
  47. UpdateConnectString();
  48. }
  49. /// <summary>使用连接凭据创建数据库连接实例。</summary>
  50. /// <param name="address">服务器地址。</param>
  51. /// <param name="store">数据库名称。</param>
  52. /// <param name="user">用户名。</param>
  53. /// <param name="pass">密码。</param>
  54. public SqlServer(string address, string store, string user, string pass)
  55. {
  56. _timeout = Timeout.Default;
  57. _address = address ?? "";
  58. _store = store ?? "";
  59. _user = user ?? "";
  60. _pass = pass ?? "";
  61. UpdateConnectString();
  62. }
  63. #endregion
  64. #region 日志。
  65. /// <summary>获取或设置日志记录。</summary>
  66. public Logger Logger { get; set; }
  67. private void LogError(string action, Exception ex, string addtion)
  68. {
  69. var logger = Logger;
  70. if (logger != null) logger.Error(this, "SQL Server", action, ex.GetType().FullName, ex.Message, addtion);
  71. }
  72. #endregion
  73. #region 实现接口。
  74. /// <summary>数据库是否已经连接。</summary>
  75. public bool Online
  76. {
  77. get
  78. {
  79. if (_db == null) return false;
  80. return (_db.State == ConnectionState.Open);
  81. }
  82. }
  83. /// <summary>连接数据库,若未连接则尝试连接,获取连接成功的状态。</summary>
  84. public bool Connect()
  85. {
  86. if (_db == null)
  87. {
  88. _db = new SqlConnection();
  89. _db.ConnectionString = ConnectionString;
  90. }
  91. else
  92. {
  93. if (_db.State == ConnectionState.Open) return true;
  94. }
  95. try
  96. {
  97. _db.Open();
  98. switch (_db.State)
  99. {
  100. case ConnectionState.Open: return true;
  101. default: return false;
  102. }
  103. }
  104. catch (Exception ex)
  105. {
  106. LogError("Connection", ex, _db.ConnectionString);
  107. Close();
  108. return false;
  109. }
  110. }
  111. /// <summary>关闭连接,并释放对象所占用的系统资源。</summary>
  112. public void Close()
  113. {
  114. if (_db != null)
  115. {
  116. _db.Close();
  117. _db.Dispose();
  118. _db = null;
  119. }
  120. }
  121. /// <summary>关闭连接,释放对象所占用的系统资源,并清除连接信息。</summary>
  122. public void Dispose()
  123. {
  124. Close();
  125. _connectionstring = "";
  126. _address = "";
  127. _store = "";
  128. _user = "";
  129. _pass = "";
  130. }
  131. /// <summary>查询。</summary>
  132. public IQuery Query(string sql) => Query(sql, null);
  133. /// <summary>查询。</summary>
  134. public IQuery Query(string sql, IEnumerable<IDataParameter> parameters)
  135. {
  136. if (string.IsNullOrWhiteSpace(sql)) return Example.InvalidQueryStatement;
  137. const string tablename = "queryresult";
  138. var connected = Connect();
  139. if (!connected) return Example.InvalidQueryConnection;
  140. var query = new Query();
  141. try
  142. {
  143. var command = new SqlCommand();
  144. command.Connection = _db;
  145. command.CommandTimeout = Timeout.Query;
  146. command.CommandText = sql;
  147. if (parameters != null)
  148. {
  149. foreach (var parameter in parameters)
  150. {
  151. if (parameter != null) command.Parameters.Add(parameter);
  152. }
  153. }
  154. using (var dataset = new DataSet())
  155. {
  156. using (var dataadapter = new SqlDataAdapter(sql, _db))
  157. {
  158. dataadapter.Fill(dataset, tablename);
  159. query.Table = dataset.Tables[tablename];
  160. }
  161. }
  162. command.Dispose();
  163. query.Success = true;
  164. }
  165. catch (Exception exception)
  166. {
  167. LogError("Query", exception, sql);
  168. query.Success = false;
  169. query.Exception = exception;
  170. }
  171. return query;
  172. }
  173. /// <summary>执行。</summary>
  174. public IExecute Execute(string sql) => Execute(sql, null);
  175. /// <summary>执行单条 Transact-SQL 语句,并加入参数。</summary>
  176. public IExecute Execute(string sql, IEnumerable<IDataParameter> parameters)
  177. {
  178. if (string.IsNullOrWhiteSpace(sql)) return Example.InvalidExecuteStatement;
  179. var connected = Connect();
  180. if (!connected) return Example.InvalidExecuteConnection;
  181. var transaction = _db.BeginTransaction();
  182. var execute = new Execute();
  183. try
  184. {
  185. var command = new SqlCommand();
  186. command.Connection = _db;
  187. command.Transaction = transaction;
  188. command.CommandTimeout = Timeout.Execute;
  189. command.CommandText = sql;
  190. if (parameters != null)
  191. {
  192. foreach (var parameter in parameters)
  193. {
  194. if (parameter != null) command.Parameters.Add(parameter);
  195. }
  196. }
  197. execute.Rows += command.ExecuteNonQuery();
  198. transaction.Commit();
  199. command.Dispose();
  200. execute.Success = true;
  201. }
  202. catch (Exception exception)
  203. {
  204. try { transaction.Rollback(); } catch { }
  205. LogError("Execute", exception, sql);
  206. execute.Success = false;
  207. execute.Exception = exception;
  208. }
  209. try { transaction.Dispose(); } catch { }
  210. return execute;
  211. }
  212. #endregion
  213. #region 属性。
  214. /// <summary>获取当前的 SqlConnection 对象。</summary>
  215. public SqlConnection Connection
  216. {
  217. get { return _db; }
  218. }
  219. /// <summary>获取或设置连接字符串。</summary>
  220. public string ConnectionString
  221. {
  222. get { return _connectionstring; }
  223. set { _connectionstring = value ?? ""; _address = ""; _store = ""; _user = ""; _pass = ""; }
  224. }
  225. /// <summary>获取或设置数据库服务器的地址。</summary>
  226. public string Address
  227. {
  228. get { return _address; }
  229. set { _address = value ?? ""; UpdateConnectString(); }
  230. }
  231. /// <summary>获取或设置数据库名称。</summary>
  232. public string Store
  233. {
  234. get { return _store; }
  235. set { _store = value ?? ""; UpdateConnectString(); }
  236. }
  237. /// <summary>获取或设置用于连接数据库服务器的用户名,为空则使用 Windows 用户登录。</summary>
  238. public string User
  239. {
  240. get { return _user; }
  241. set { _user = value ?? ""; UpdateConnectString(); }
  242. }
  243. /// <summary>获取或设置用于连接数据库服务器的密码。</summary>
  244. public string Pass
  245. {
  246. get { return _pass; }
  247. set { _pass = value ?? ""; UpdateConnectString(); }
  248. }
  249. /// <summary>获取或设置超时。</summary>
  250. public Timeout Timeout
  251. {
  252. get { return _timeout; }
  253. set { _timeout = value; }
  254. }
  255. #endregion
  256. #region 方法。
  257. /// <summary>指定连接凭据后,是否符合连接要求。</summary>
  258. public bool Proven()
  259. {
  260. return Proven(_address, _store, _user, _pass);
  261. }
  262. private void UpdateConnectString()
  263. {
  264. _connectionstring = "";
  265. _connectionstring += "data source = " + _address + "; ";
  266. _connectionstring += "initial catalog = " + _store + "; ";
  267. if (string.IsNullOrEmpty(User))
  268. {
  269. _connectionstring += "integrated security = sspi; ";
  270. }
  271. else
  272. {
  273. _connectionstring += "user id = " + _user + "; ";
  274. if (!string.IsNullOrEmpty(_pass)) _connectionstring += "password = " + _pass + "; ";
  275. }
  276. _connectionstring += "connection timeout = " + Timeout.Connect.ToString() + ";";
  277. }
  278. /// <summary>查询数据库中的所有表名。</summary>
  279. public List<string> TableNames()
  280. {
  281. var list = new List<string>();
  282. if (Connect())
  283. {
  284. var sql = "select [name] from [sysobjects] where [type] = 'u' order by [name]; ";
  285. var query = (Query)Query(sql);
  286. for (int r = 0; r < query.Rows; r++)
  287. {
  288. var cell = query.Text(r, 0);
  289. if (TextUtility.IsBlank(cell)) continue;
  290. list.Add(cell);
  291. }
  292. query.Dispose();
  293. }
  294. return list;
  295. }
  296. /// <summary>查询数据库实例中的所有数据库名。</summary>
  297. public List<string> StoreNames()
  298. {
  299. var list = new List<string>();
  300. if (Connect())
  301. {
  302. var sql = "select [name] from [master]..[sysdatabases] order by [name]; ";
  303. var query = (Query)Query(sql);
  304. for (int r = 0; r < query.Rows; r++)
  305. {
  306. var cell = query.Text(r, 0);
  307. if (TextUtility.IsBlank(cell)) continue;
  308. if (cell == "master") continue;
  309. if (cell == "model") continue;
  310. if (cell == "msdb") continue;
  311. if (cell == "tempdb") continue;
  312. list.Add(cell);
  313. }
  314. query.Dispose();
  315. }
  316. return list;
  317. }
  318. /// <summary>查询表中的所有列名。</summary>
  319. public List<string> ColumnNames(string tableName)
  320. {
  321. var list = new List<string>();
  322. if (Connect())
  323. {
  324. var table = TextUtility.AntiInject(tableName);
  325. var sql = TextUtility.Merge("select [name] from [syscolumns] where [id] = object_id('", table, "'); ");
  326. var query = (Query)Query(sql);
  327. for (int r = 0; r < query.Rows; r++)
  328. {
  329. var cell = query.Text(r, 0);
  330. if (TextUtility.IsBlank(cell)) continue;
  331. list.Add(cell);
  332. }
  333. query.Dispose();
  334. }
  335. return list;
  336. }
  337. /// <summary>创建表,当表不存在时创建表,当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。</summary>
  338. public string Initialize(Record model) => model == null ? "参数无效。" : Initialize(model);
  339. /// <summary>创建表,当表不存在时创建表,当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。</summary>
  340. public string Initialize(Type model)
  341. {
  342. var structure = null as TableStructure;
  343. try { structure = TableStructure.ParseModel(model); }
  344. catch (Exception exception) { return exception.Message; }
  345. // 连接数据库。
  346. if (!Connect()) return "连接数据库失败。";
  347. // 检查现存表。
  348. var exists = false;
  349. var tables = TableNames();
  350. if (tables.Count > 0)
  351. {
  352. var lower = structure.Table.ToLower();
  353. foreach (var table in tables)
  354. {
  355. if (TextUtility.IsBlank(table)) continue;
  356. if (table.ToLower() == lower)
  357. {
  358. exists = true;
  359. break;
  360. }
  361. }
  362. }
  363. if (exists)
  364. {
  365. // 获取已存在的列名。
  366. var columns = ColumnNames(structure.Table);
  367. if (columns.Count > 0)
  368. {
  369. var lower = new List<string>();
  370. foreach (var column in columns)
  371. {
  372. if (TextUtility.IsBlank(column)) continue;
  373. lower.Add(column.ToLower());
  374. }
  375. columns = lower;
  376. }
  377. // 增加列。
  378. foreach (var column in structure.Columns.Values)
  379. {
  380. // 检查 Independent 特性。
  381. if (structure.Independent && column.Independent) continue;
  382. // 去重。
  383. var lower = column.Field.ToLower();
  384. if (columns.Contains(lower)) continue;
  385. var type = GetColumnDeclaration(column);
  386. if (type == TextUtility.EmptyString) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  387. var sql = TextUtility.Merge("alter table [", structure.Table, "] add ", type, "; ");
  388. var execute = Execute(sql);
  389. if (execute.Success == false) return execute.Error;
  390. }
  391. return TextUtility.EmptyString;
  392. }
  393. else
  394. {
  395. var sqlcolumns = new List<string>();
  396. foreach (var kvp in structure.Columns)
  397. {
  398. var property = kvp.Key;
  399. var column = kvp.Value;
  400. // 检查 Independent 特性。
  401. if (structure.Independent && column.Independent) continue;
  402. var type = GetColumnDeclaration(column);
  403. if (!column.Independent && property == "Key") type = type + " primary key";
  404. if (type == TextUtility.EmptyString) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  405. sqlcolumns.Add(type);
  406. }
  407. var sql = TextUtility.Merge("create table [", structure.Table, "](", string.Join(", ", sqlcolumns), "); ");
  408. var execute = Execute(sql);
  409. if (execute.Success) return TextUtility.EmptyString;
  410. return execute.Error;
  411. }
  412. }
  413. /// <summary>插入记录。成功时候返回空字符串,发生异常时返回异常信息。</summary>
  414. public string Insert(Record record)
  415. {
  416. if (record == null) return "参数无效。";
  417. var type = record.GetType();
  418. record.FixProperties();
  419. var structure = null as TableStructure;
  420. try { structure = TableStructure.ParseModel(record); }
  421. catch (Exception exception) { return exception.Message; }
  422. var parameters = structure.CreateDataParameters(record, CreateDataParameter);
  423. var sql = GenerateInsertStatement(structure.Table, parameters);
  424. var execute = Execute(sql, parameters);
  425. if (execute.Success) return TextUtility.EmptyString;
  426. return execute.Error;
  427. }
  428. /// <summary>
  429. /// <para>更新记录,实体中的 Created 和 Key 属性不被更新。成功时返回空字符串,发生异常时返回异常信息。</para>
  430. /// <para>无法更新拥有 Independent 特性的模型。</para>
  431. /// </summary>
  432. public string Update(Record record)
  433. {
  434. if (record == null) return "参数无效。";
  435. var type = record.GetType();
  436. record.FixProperties();
  437. record.Updated = ClockUtility.LucidNow;
  438. var structure = null as TableStructure;
  439. try { structure = TableStructure.ParseModel(record); }
  440. catch (Exception exception) { return exception.Message; }
  441. // 检查 Independent 特性。
  442. if (structure.Independent) return "无法更新拥有 Independent 特性的模型。";
  443. var parameters = structure.CreateDataParameters(record, CreateDataParameter, "_created", "_key");
  444. var sql = GenerateUpdateStatement(structure.Table, record.Key, parameters);
  445. var execute = Execute(sql, parameters);
  446. if (execute.Success) return TextUtility.EmptyString;
  447. return execute.Error;
  448. }
  449. /// <summary>获取具有指定 Key 的记录。</summary>
  450. public Result<T> Get<T>(string key, long flag = 0) where T : Record
  451. {
  452. var k = TextUtility.SafeKey(key);
  453. if (TextUtility.IsBlank(k) == false)
  454. {
  455. try
  456. {
  457. var type = typeof(T);
  458. var ts = TableStructure.ParseModel(type);
  459. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" _flag=", flag.ToString(), " and");
  460. var query = (Query)Query(TextUtility.Merge("select top 1 * from [", ts.Table, "] where", f, " _key='", k, "'; "));
  461. var list = query.Fill<T>();
  462. query.Dispose();
  463. if (list.Count > 0) return new Result<T>(list[0]);
  464. }
  465. catch (Exception ex)
  466. {
  467. return new Result<T>(ex);
  468. }
  469. }
  470. return new Result<T>(new Exception("参数无效。"));
  471. }
  472. /// <summary>获取记录。</summary>
  473. public Result<List<T>> Query<T>(long flag = 0) where T : Record
  474. {
  475. try
  476. {
  477. var type = typeof(T);
  478. var ts = TableStructure.ParseModel(type);
  479. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where _flag=", flag.ToString());
  480. var query = (Query)Query(TextUtility.Merge("select * from [", ts.Table, "]", f, "; "));
  481. var list = query.Fill<T>();
  482. query.Dispose();
  483. return new Result<List<T>>(list);
  484. }
  485. catch (Exception ex)
  486. {
  487. return new Result<List<T>>(ex);
  488. }
  489. }
  490. /// <summary>获取按指定语句查询到的所有记录。</summary>
  491. public Result<List<T>> Query<T>(string sql) where T : Record
  492. {
  493. var query = (Query)Query(sql);
  494. if (query.Exception == null)
  495. {
  496. var list = query.Fill<T>();
  497. query.Dispose();
  498. return new Result<List<T>>(list);
  499. }
  500. else
  501. {
  502. var result = new Result<List<T>>(query.Exception);
  503. query.Dispose();
  504. return result;
  505. }
  506. }
  507. /// <summary>查询有效的 Key 值。</summary>
  508. public Result<List<string>> Keys(Type model, long flag = 0)
  509. {
  510. if (model != null)
  511. {
  512. try
  513. {
  514. var type = model;
  515. var list = new List<string>();
  516. var ts = TableStructure.ParseModel(type);
  517. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where _flag=", flag.ToString());
  518. var query = (Query)Query(TextUtility.Merge("select _key from [", ts.Table, "]", f, "; "));
  519. for (var r = 0; r < query.Rows; r++)
  520. {
  521. var cell = TextUtility.Trim(query.Text(r));
  522. if (cell.Length > 0) list.Add(cell);
  523. }
  524. query.Dispose();
  525. return new Result<List<string>>(list);
  526. }
  527. catch (Exception ex)
  528. {
  529. return new Result<List<string>>(ex);
  530. }
  531. }
  532. return new Result<List<string>>(new Exception("参数无效。"));
  533. }
  534. /// <summary>查询有效的 Key 值。</summary>
  535. public Result<List<string>> Keys<T>(long flag = 0) where T : Record => Keys(typeof(T), flag);
  536. #endregion
  537. #region 静态方法。
  538. private static string GetColumnDeclaration(ColumnAttribute column)
  539. {
  540. var type = TextUtility.EmptyString;
  541. var vcolumn = column;
  542. var length = Math.Max(0, vcolumn.Length);
  543. switch (vcolumn.Type)
  544. {
  545. case ColumnType.Integer:
  546. type = "bigint";
  547. break;
  548. case ColumnType.Float:
  549. type = "float";
  550. break;
  551. case ColumnType.Binary:
  552. type = "image";
  553. break;
  554. case ColumnType.DateTime:
  555. type = "datetime";
  556. break;
  557. case ColumnType.VarChar:
  558. type = TextUtility.Merge("varchar(", Math.Min(8000, length).ToString(), ")");
  559. break;
  560. case ColumnType.VarChar255:
  561. type = TextUtility.Merge("varchar(255)");
  562. break;
  563. case ColumnType.VarCharMax:
  564. type = TextUtility.Merge("varchar(max)");
  565. break;
  566. case ColumnType.Text:
  567. type = TextUtility.Merge("text");
  568. break;
  569. case ColumnType.NVarChar:
  570. type = TextUtility.Merge("nvarchar(", Math.Min(4000, length).ToString(), ")");
  571. break;
  572. case ColumnType.NVarChar255:
  573. type = TextUtility.Merge("nvarchar(255)");
  574. break;
  575. case ColumnType.NVarCharMax:
  576. type = TextUtility.Merge("nvarchar(max)");
  577. break;
  578. case ColumnType.NText:
  579. type = TextUtility.Merge("ntext");
  580. break;
  581. default:
  582. return TextUtility.EmptyString;
  583. }
  584. return TextUtility.Merge("[", vcolumn.Field, "] ", type);
  585. }
  586. /// <summary>创建参数。</summary>
  587. /// <exception cref="ArgumentNullException"></exception>
  588. /// <exception cref="InvalidOperationException"></exception>
  589. internal static SqlParameter CreateDataParameter(Parameter parameter)
  590. {
  591. if (parameter == null) throw new InvalidOperationException("参数无效。");
  592. return CreateDataParameter(parameter.Name, parameter.Type, parameter.Size, parameter.Value);
  593. }
  594. /// <summary>创建参数。</summary>
  595. public static SqlParameter CreateDataParameter(string name, ColumnType type, Int32 size, object value)
  596. {
  597. var vname = TextUtility.Trim(name);
  598. if (TextUtility.IsBlank(vname)) return null;
  599. var vtype = SqlDbType.BigInt;
  600. switch (type)
  601. {
  602. case ColumnType.Binary:
  603. vtype = SqlDbType.Image;
  604. break;
  605. case ColumnType.Integer:
  606. vtype = SqlDbType.BigInt;
  607. break;
  608. case ColumnType.Float:
  609. vtype = SqlDbType.Float;
  610. break;
  611. case ColumnType.DateTime:
  612. vtype = SqlDbType.DateTime;
  613. break;
  614. case ColumnType.VarChar:
  615. case ColumnType.VarChar255:
  616. case ColumnType.VarCharMax:
  617. vtype = SqlDbType.VarChar;
  618. break;
  619. case ColumnType.NVarChar:
  620. case ColumnType.NVarChar255:
  621. case ColumnType.NVarCharMax:
  622. vtype = SqlDbType.VarChar;
  623. break;
  624. case ColumnType.Text:
  625. vtype = SqlDbType.Text;
  626. break;
  627. case ColumnType.NText:
  628. vtype = SqlDbType.NText;
  629. break;
  630. default:
  631. throw new InvalidOperationException(TextUtility.Merge("类型 ", type.ToString(), " 不受支持。"));
  632. }
  633. var vsize = size;
  634. switch (type)
  635. {
  636. case ColumnType.VarChar:
  637. vsize = NumberUtility.RestrictValue(vsize, 0, 8000);
  638. break;
  639. case ColumnType.NVarChar:
  640. vsize = NumberUtility.RestrictValue(vsize, 0, 4000);
  641. break;
  642. case ColumnType.VarChar255:
  643. case ColumnType.NVarChar255:
  644. vsize = NumberUtility.RestrictValue(vsize, 0, 255);
  645. break;
  646. default:
  647. vsize = 0;
  648. break;
  649. }
  650. var vvalue = value;
  651. if (vvalue is string && vvalue != null && vsize > 0)
  652. {
  653. vvalue = TextUtility.RestrictLength((string)vvalue, vsize);
  654. }
  655. var parameter = new SqlParameter();
  656. parameter.ParameterName = vname;
  657. parameter.SqlDbType = vtype;
  658. parameter.Value = vvalue;
  659. if (vsize > 0) parameter.Size = vsize;
  660. return parameter;
  661. }
  662. /// <summary>创建参数。</summary>
  663. public static SqlParameter CreateDataParameter(String name, SqlDbType type, Int32 size, Object value)
  664. {
  665. if (value is string && value != null && size > 0)
  666. {
  667. value = TextUtility.RestrictLength((string)value, (int)size);
  668. }
  669. var p = new SqlParameter();
  670. p.ParameterName = name ?? "";
  671. p.SqlDbType = type;
  672. p.Size = size;
  673. p.Value = value;
  674. return p;
  675. }
  676. /// <summary>创建参数。</summary>
  677. public static SqlParameter CreateDataParameter(String name, SqlDbType type, Object value)
  678. {
  679. var p = new SqlParameter();
  680. p.ParameterName = name ?? "";
  681. p.SqlDbType = type;
  682. p.Value = value;
  683. return p;
  684. }
  685. ///// <summary>枚举本地网络中服务器的名称。</summary>
  686. //public static List<string> EnumerateServer()
  687. //{
  688. // // 表中列名:ServerName、InstanceName、IsClustered、Version。
  689. // var table = SqlDataSourceEnumerator.Instance.GetDataSources();
  690. // var query = new Query();
  691. // query.Success = table != null;
  692. // query.Table = table;
  693. // var list = new List<string>();
  694. // for (int i = 0; i < query.Rows; i++)
  695. // {
  696. // var sn = query.Text(i, "ServerName");
  697. // if (!string.IsNullOrEmpty(sn)) list.Add(sn);
  698. // }
  699. // query.Dispose();
  700. // return list;
  701. //}
  702. /// <summary>指定的连接凭据是否符合连接要求。</summary>
  703. public static bool Proven(SqlServer sqlserver)
  704. {
  705. return Proven(sqlserver._address, sqlserver._store, sqlserver._user, sqlserver._pass);
  706. }
  707. /// <summary>指定的连接凭据是否符合连接要求,默认指定 master 数据库。</summary>
  708. public static bool Proven(string address, string user, string pass) => Proven(address, "master", user, pass);
  709. /// <summary>指定的连接凭据是否符合连接要求。</summary>
  710. public static bool Proven(string address, string store, string user, string pass)
  711. {
  712. var a = string.IsNullOrEmpty(address);
  713. var s = string.IsNullOrEmpty(store);
  714. var u = string.IsNullOrEmpty(user);
  715. var p = string.IsNullOrEmpty(pass);
  716. if (a) return false;
  717. if (s) return false;
  718. if (u && !p) return false;
  719. return true;
  720. }
  721. #endregion
  722. #region Linq Utility
  723. private static string GetParameterName(string parameter)
  724. {
  725. var name = TextUtility.AntiInject(parameter, 255);
  726. if (name.StartsWith("@") && name.Length > 1)
  727. {
  728. name = name.Substring(1, name.Length - 1);
  729. }
  730. return name;
  731. }
  732. private static string GetParameterName(IDataParameter parameter)
  733. {
  734. var name = TextUtility.EmptyString;
  735. if (parameter != null)
  736. {
  737. name = GetParameterName(parameter.ParameterName);
  738. }
  739. return name;
  740. }
  741. private static List<string> GetParametersNames(IEnumerable<IDataParameter> parameters)
  742. {
  743. var columns = new List<string>();
  744. if (parameters != null)
  745. {
  746. foreach (var parameter in parameters)
  747. {
  748. var name = GetParameterName(parameter);
  749. var isblank = TextUtility.IsBlank(name);
  750. if (isblank) continue;
  751. columns.Add(name);
  752. }
  753. }
  754. return columns;
  755. }
  756. private static string GenerateInsertStatement(string table, List<string> columns)
  757. {
  758. var result = TextUtility.EmptyString;
  759. var vtable = TextUtility.AntiInject(table, 255);
  760. if (columns != null && !TextUtility.IsBlank(vtable))
  761. {
  762. var count = 0;
  763. var names = new List<string>();
  764. var values = new List<string>();
  765. foreach (var column in columns)
  766. {
  767. //names.Add(TextGenerator.Merge("[", column, "]"));
  768. names.Add(TextUtility.Merge(column));
  769. values.Add("@" + column);
  770. count += 1;
  771. }
  772. var text = new StringBuilder();
  773. if (count > 0)
  774. {
  775. text.Append("insert into [", vtable, "](", string.Join(", ", names), ") ");
  776. text.Append("values(", string.Join(", ", values), "); ");
  777. }
  778. result = text.ToString();
  779. }
  780. return result;
  781. }
  782. private static string GenerateUpdateStatement(string table, string key, List<string> columns)
  783. {
  784. var result = TextUtility.EmptyString;
  785. var vtable = TextUtility.AntiInject(table, 255);
  786. var vkey = TextUtility.AntiInject(key, 255);
  787. if (columns != null && !TextUtility.IsBlank(vtable) && !TextUtility.IsBlank(vkey))
  788. {
  789. var items = new List<string>();
  790. foreach (var column in columns)
  791. {
  792. items.Add(TextUtility.Merge("[", column, "]=@", column));
  793. }
  794. if (items.Count > 0)
  795. {
  796. result = TextUtility.Merge("update [", vtable, "] set ", string.Join(", ", items), " where [_key]='", vkey, "'; ");
  797. }
  798. }
  799. return result;
  800. }
  801. /// <summary>生成 INSERT INTO 语句。表名必须有效,无有效参数时将获取空结果。</summary>
  802. /// <exception cref="System.ArgumentException"></exception>
  803. /// <exception cref="System.ArgumentNullException"></exception>
  804. private static string GenerateInsertStatement(string table, IEnumerable<IDataParameter> parameters)
  805. {
  806. if (table == null) throw new ArgumentNullException(nameof(table));
  807. var tableName = TextUtility.AntiInject(table, 255);
  808. if (TextUtility.IsBlank(tableName)) throw new ArgumentException("表名无效。", nameof(table));
  809. var vcolumns = GetParametersNames(parameters);
  810. if (vcolumns.Count < 1) return TextUtility.EmptyString;
  811. return GenerateInsertStatement(tableName, vcolumns);
  812. }
  813. /// <summary>生成 UPDATE 语句,键字段名为“_key”。表名必须有效,键值必须有效,无有效参数时将获取空结果。</summary>
  814. /// <exception cref="System.ArgumentException"></exception>
  815. /// <exception cref="System.ArgumentNullException"></exception>
  816. private static string GenerateUpdateStatement(string table, string key, IEnumerable<IDataParameter> parameters)
  817. {
  818. if (table == null) throw new ArgumentNullException(nameof(table));
  819. var t = TextUtility.AntiInject(table, 255);
  820. if (TextUtility.IsBlank(t)) throw new ArgumentException("表名无效。", nameof(table));
  821. if (key == null) throw new ArgumentNullException("argKey");
  822. var k = TextUtility.AntiInject(key, 255);
  823. if (TextUtility.IsBlank(k)) throw new ArgumentException("键值无效。", nameof(table));
  824. var columes = GetParametersNames(parameters);
  825. if (columes.Count < 1) return TextUtility.EmptyString;
  826. return GenerateUpdateStatement(t, k, columes);
  827. }
  828. #endregion
  829. }
  830. }
  831. #endif