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.

974 lines
35 KiB

  1. #if NET40 || NET461
  2. /* 2021.02.20 */
  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, 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> QueryAllTableNames()
  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> QueryAllStoreNames()
  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> QueryAllColumnNames(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 CreateTable(Record model)
  339. {
  340. if (model == null) return "参数无效。";
  341. var type = model.GetType();
  342. var error = CreateTable(type);
  343. return error;
  344. }
  345. /// <summary>创建表,当表不存在时创建表,当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。</summary>
  346. public string CreateTable(Type model)
  347. {
  348. var structure = null as TableStructure;
  349. try { structure = TableStructure.ParseModel(model); }
  350. catch (Exception exception) { return exception.Message; }
  351. // 连接数据库。
  352. if (!Connect()) return "连接数据库失败。";
  353. // 检查现存表。
  354. var exists = false;
  355. var tables = QueryAllTableNames();
  356. if (tables.Count > 0)
  357. {
  358. var lower = structure.Table.ToLower();
  359. foreach (var table in tables)
  360. {
  361. if (TextUtility.IsBlank(table)) continue;
  362. if (table.ToLower() == lower)
  363. {
  364. exists = true;
  365. break;
  366. }
  367. }
  368. }
  369. if (exists)
  370. {
  371. // 获取已存在的列名。
  372. var columns = QueryAllColumnNames(structure.Table);
  373. if (columns.Count > 0)
  374. {
  375. var lower = new List<string>();
  376. foreach (var column in columns)
  377. {
  378. if (TextUtility.IsBlank(column)) continue;
  379. lower.Add(column.ToLower());
  380. }
  381. columns = lower;
  382. }
  383. // 增加列。
  384. foreach (var column in structure.Columns.Values)
  385. {
  386. // 检查 Independent 特性。
  387. if (structure.Independent && column.Independent) continue;
  388. // 去重。
  389. var lower = column.Field.ToLower();
  390. if (columns.Contains(lower)) continue;
  391. var type = GetColumnDeclaration(column);
  392. if (type == TextUtility.EmptyString) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  393. var sql = TextUtility.Merge("alter table [", structure.Table, "] add ", type, "; ");
  394. var execute = Execute(sql);
  395. if (execute.Success == false) return execute.Error;
  396. }
  397. return TextUtility.EmptyString;
  398. }
  399. else
  400. {
  401. var sqlcolumns = new List<string>();
  402. foreach (var kvp in structure.Columns)
  403. {
  404. var property = kvp.Key;
  405. var column = kvp.Value;
  406. // 检查 Independent 特性。
  407. if (structure.Independent && column.Independent) continue;
  408. var type = GetColumnDeclaration(column);
  409. if (!column.Independent && property == "Key") type = type + " primary key";
  410. if (type == TextUtility.EmptyString) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  411. sqlcolumns.Add(type);
  412. }
  413. var sql = TextUtility.Merge("create table [", structure.Table, "](", string.Join(", ", sqlcolumns), "); ");
  414. var execute = Execute(sql);
  415. if (execute.Success) return TextUtility.EmptyString;
  416. return execute.Error;
  417. }
  418. }
  419. /// <summary>插入记录。成功时候返回空字符串,发生异常时返回异常信息。</summary>
  420. public string Insert(Record entity)
  421. {
  422. if (entity == null) return "参数无效。";
  423. var type = entity.GetType();
  424. entity.FixProperties();
  425. var structure = null as TableStructure;
  426. try { structure = TableStructure.ParseModel(entity); }
  427. catch (Exception exception) { return exception.Message; }
  428. var parameters = structure.CreateDataParameters(entity, CreateDataParameter);
  429. var sql = GenerateInsertStatement(structure.Table, parameters);
  430. var execute = Execute(sql, parameters);
  431. if (execute.Success) return TextUtility.EmptyString;
  432. return execute.Error;
  433. }
  434. /// <summary>
  435. /// <para>更新记录,实体中的 Created 和 Key 属性不被更新。成功时返回空字符串,发生异常时返回异常信息。</para>
  436. /// <para>无法更新拥有 Independent 特性的模型。</para>
  437. /// </summary>
  438. public string Update(Record entity)
  439. {
  440. if (entity == null) return "参数无效。";
  441. var type = entity.GetType();
  442. entity.FixProperties();
  443. entity.Updated = ClockUtility.LucidNow;
  444. var structure = null as TableStructure;
  445. try { structure = TableStructure.ParseModel(entity); }
  446. catch (Exception exception) { return exception.Message; }
  447. // 检查 Independent 特性。
  448. if (structure.Independent) return "无法更新拥有 Independent 特性的模型。";
  449. var parameters = structure.CreateDataParameters(entity, CreateDataParameter, "_created", "_key");
  450. var sql = GenerateUpdateStatement(structure.Table, entity.Key, parameters);
  451. var execute = Execute(sql, parameters);
  452. if (execute.Success) return TextUtility.EmptyString;
  453. return execute.Error;
  454. }
  455. /// <summary>获取具有指定 Key 的记录。</summary>
  456. public Result<T> QueryRecord<T>(string key, long flag = 0) where T : Record
  457. {
  458. var k = TextUtility.SafeKey(key);
  459. if (TextUtility.IsBlank(k) == false)
  460. {
  461. try
  462. {
  463. var type = typeof(T);
  464. var ts = TableStructure.ParseModel(type);
  465. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" _flag=", flag.ToString(), " and");
  466. var query = (Query)Query(TextUtility.Merge("select top 1 * from [", ts.Table, "] where", f, " _key='", k, "'; "));
  467. var list = query.Fill<T>();
  468. query.Dispose();
  469. if (list.Count > 0) return new Result<T>(list[0]);
  470. }
  471. catch (Exception ex)
  472. {
  473. return new Result<T>(ex);
  474. }
  475. }
  476. return new Result<T>(new Exception("参数无效。"));
  477. }
  478. /// <summary>获取记录。</summary>
  479. public Result<List<T>> QueryRecords<T>(long flag = 0) where T : Record
  480. {
  481. try
  482. {
  483. var type = typeof(T);
  484. var ts = TableStructure.ParseModel(type);
  485. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where _flag=", flag.ToString());
  486. var query = (Query)Query(TextUtility.Merge("select * from [", ts.Table, "]", f, "; "));
  487. var list = query.Fill<T>();
  488. query.Dispose();
  489. return new Result<List<T>>(list);
  490. }
  491. catch (Exception ex)
  492. {
  493. return new Result<List<T>>(ex);
  494. }
  495. }
  496. /// <summary>获取按指定语句查询到的所有记录。</summary>
  497. public Result<List<T>> Query<T>(string sql) where T : Record
  498. {
  499. var query = (Query)Query(sql);
  500. if (query.Exception == null)
  501. {
  502. var list = query.Fill<T>();
  503. query.Dispose();
  504. return new Result<List<T>>(list);
  505. }
  506. else
  507. {
  508. var result = new Result<List<T>>(query.Exception);
  509. query.Dispose();
  510. return result;
  511. }
  512. }
  513. /// <summary>查询有效的 Key 值。</summary>
  514. public Result<List<string>> QueryKeys(Type model, long flag = 0)
  515. {
  516. if (model != null)
  517. {
  518. try
  519. {
  520. var type = model;
  521. var list = new List<string>();
  522. var ts = TableStructure.ParseModel(type);
  523. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where _flag=", flag.ToString());
  524. var query = (Query)Query(TextUtility.Merge("select _key from [", ts.Table, "]", f, "; "));
  525. for (var r = 0; r < query.Rows; r++)
  526. {
  527. var cell = TextUtility.Trim(query.Text(r));
  528. if (cell.Length > 0) list.Add(cell);
  529. }
  530. query.Dispose();
  531. return new Result<List<string>>(list);
  532. }
  533. catch (Exception ex)
  534. {
  535. return new Result<List<string>>(ex);
  536. }
  537. }
  538. return new Result<List<string>>(new Exception("参数无效。"));
  539. }
  540. /// <summary>查询有效的 Key 值。</summary>
  541. public Result<List<string>> QueryKeys<T>(long flag = 0) where T : Record
  542. {
  543. try
  544. {
  545. var type = typeof(T);
  546. var ts = TableStructure.ParseModel(type);
  547. var f = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where _flag=", flag.ToString());
  548. var query = (Query)Query(TextUtility.Merge("select _key from [", ts.Table, "]", f, "; "));
  549. var list = new List<string>();
  550. for (var r = 0; r < query.Rows; r++)
  551. {
  552. var cell = TextUtility.Trim(query.Text(r));
  553. if (cell.Length > 0) list.Add(cell);
  554. }
  555. query.Dispose();
  556. return new Result<List<string>>(list);
  557. }
  558. catch (Exception ex)
  559. {
  560. return new Result<List<string>>(ex);
  561. }
  562. }
  563. #endregion
  564. #region 静态方法。
  565. private static string GetColumnDeclaration(ColumnAttribute column)
  566. {
  567. var type = TextUtility.EmptyString;
  568. var vcolumn = column;
  569. var length = Math.Max(0, vcolumn.Length);
  570. switch (vcolumn.Type)
  571. {
  572. case ColumnType.Integer:
  573. type = "bigint";
  574. break;
  575. case ColumnType.Float:
  576. type = "float";
  577. break;
  578. case ColumnType.Binary:
  579. type = "image";
  580. break;
  581. case ColumnType.DateTime:
  582. type = "datetime";
  583. break;
  584. case ColumnType.VarChar:
  585. type = TextUtility.Merge("varchar(", Math.Min(8000, length).ToString(), ")");
  586. break;
  587. case ColumnType.VarChar255:
  588. type = TextUtility.Merge("varchar(255)");
  589. break;
  590. case ColumnType.VarCharMax:
  591. type = TextUtility.Merge("varchar(max)");
  592. break;
  593. case ColumnType.Text:
  594. type = TextUtility.Merge("text");
  595. break;
  596. case ColumnType.NVarChar:
  597. type = TextUtility.Merge("nvarchar(", Math.Min(4000, length).ToString(), ")");
  598. break;
  599. case ColumnType.NVarChar255:
  600. type = TextUtility.Merge("nvarchar(255)");
  601. break;
  602. case ColumnType.NVarCharMax:
  603. type = TextUtility.Merge("nvarchar(max)");
  604. break;
  605. case ColumnType.NText:
  606. type = TextUtility.Merge("ntext");
  607. break;
  608. default:
  609. return TextUtility.EmptyString;
  610. }
  611. return TextUtility.Merge("[", vcolumn.Field, "] ", type);
  612. }
  613. /// <summary>创建参数。</summary>
  614. /// <exception cref="ArgumentNullException"></exception>
  615. /// <exception cref="InvalidOperationException"></exception>
  616. internal static SqlParameter CreateDataParameter(Parameter parameter)
  617. {
  618. if (parameter == null) throw new InvalidOperationException("参数无效。");
  619. return CreateDataParameter(parameter.Name, parameter.Type, parameter.Size, parameter.Value);
  620. }
  621. /// <summary>创建参数。</summary>
  622. public static SqlParameter CreateDataParameter(string name, ColumnType type, Int32 size, object value)
  623. {
  624. var vname = TextUtility.Trim(name);
  625. if (TextUtility.IsBlank(vname)) return null;
  626. var vtype = SqlDbType.BigInt;
  627. switch (type)
  628. {
  629. case ColumnType.Binary:
  630. vtype = SqlDbType.Image;
  631. break;
  632. case ColumnType.Integer:
  633. vtype = SqlDbType.BigInt;
  634. break;
  635. case ColumnType.Float:
  636. vtype = SqlDbType.Float;
  637. break;
  638. case ColumnType.DateTime:
  639. vtype = SqlDbType.DateTime;
  640. break;
  641. case ColumnType.VarChar:
  642. case ColumnType.VarChar255:
  643. case ColumnType.VarCharMax:
  644. vtype = SqlDbType.VarChar;
  645. break;
  646. case ColumnType.NVarChar:
  647. case ColumnType.NVarChar255:
  648. case ColumnType.NVarCharMax:
  649. vtype = SqlDbType.VarChar;
  650. break;
  651. case ColumnType.Text:
  652. vtype = SqlDbType.Text;
  653. break;
  654. case ColumnType.NText:
  655. vtype = SqlDbType.NText;
  656. break;
  657. default:
  658. throw new InvalidOperationException(TextUtility.Merge("类型 ", type.ToString(), " 不受支持。"));
  659. }
  660. var vsize = size;
  661. switch (type)
  662. {
  663. case ColumnType.VarChar:
  664. vsize = NumberUtility.RestrictValue(vsize, 0, 8000);
  665. break;
  666. case ColumnType.NVarChar:
  667. vsize = NumberUtility.RestrictValue(vsize, 0, 4000);
  668. break;
  669. case ColumnType.VarChar255:
  670. case ColumnType.NVarChar255:
  671. vsize = NumberUtility.RestrictValue(vsize, 0, 255);
  672. break;
  673. default:
  674. vsize = 0;
  675. break;
  676. }
  677. var vvalue = value;
  678. if (vvalue is string && vvalue != null && vsize > 0)
  679. {
  680. vvalue = TextUtility.RestrictLength((string)vvalue, vsize);
  681. }
  682. var parameter = new SqlParameter();
  683. parameter.ParameterName = vname;
  684. parameter.SqlDbType = vtype;
  685. parameter.Value = vvalue;
  686. if (vsize > 0) parameter.Size = vsize;
  687. return parameter;
  688. }
  689. /// <summary>创建参数。</summary>
  690. public static SqlParameter CreateDataParameter(String name, SqlDbType type, Int32 size, Object value)
  691. {
  692. if (value is string && value != null && size > 0)
  693. {
  694. value = TextUtility.RestrictLength((string)value, (int)size);
  695. }
  696. var p = new SqlParameter();
  697. p.ParameterName = name ?? "";
  698. p.SqlDbType = type;
  699. p.Size = size;
  700. p.Value = value;
  701. return p;
  702. }
  703. /// <summary>创建参数。</summary>
  704. public static SqlParameter CreateDataParameter(String name, SqlDbType type, Object value)
  705. {
  706. var p = new SqlParameter();
  707. p.ParameterName = name ?? "";
  708. p.SqlDbType = type;
  709. p.Value = value;
  710. return p;
  711. }
  712. ///// <summary>枚举本地网络中服务器的名称。</summary>
  713. //public static List<string> EnumerateServer()
  714. //{
  715. // // 表中列名:ServerName、InstanceName、IsClustered、Version。
  716. // var table = SqlDataSourceEnumerator.Instance.GetDataSources();
  717. // var query = new Query();
  718. // query.Success = table != null;
  719. // query.Table = table;
  720. // var list = new List<string>();
  721. // for (int i = 0; i < query.Rows; i++)
  722. // {
  723. // var sn = query.Text(i, "ServerName");
  724. // if (!string.IsNullOrEmpty(sn)) list.Add(sn);
  725. // }
  726. // query.Dispose();
  727. // return list;
  728. //}
  729. /// <summary>指定的连接凭据是否符合连接要求。</summary>
  730. public static bool Proven(SqlServer sqlserver)
  731. {
  732. return Proven(sqlserver._address, sqlserver._store, sqlserver._user, sqlserver._pass);
  733. }
  734. /// <summary>指定的连接凭据是否符合连接要求,默认指定 master 数据库。</summary>
  735. public static bool Proven(string address, string user, string pass)
  736. {
  737. return Proven(address, "master", user, pass);
  738. }
  739. /// <summary>指定的连接凭据是否符合连接要求。</summary>
  740. public static bool Proven(string address, string store, string user, string pass)
  741. {
  742. var a = string.IsNullOrEmpty(address);
  743. var s = string.IsNullOrEmpty(store);
  744. var u = string.IsNullOrEmpty(user);
  745. var p = string.IsNullOrEmpty(pass);
  746. if (a) return false;
  747. if (s) return false;
  748. if (u && !p) return false;
  749. return true;
  750. }
  751. #endregion
  752. #region Linq Utility
  753. private static string GetParameterName(string parameter)
  754. {
  755. var name = TextUtility.AntiInject(parameter, 255);
  756. if (name.StartsWith("@") && name.Length > 1)
  757. {
  758. name = name.Substring(1, name.Length - 1);
  759. }
  760. return name;
  761. }
  762. private static string GetParameterName(IDataParameter parameter)
  763. {
  764. var name = TextUtility.EmptyString;
  765. if (parameter != null)
  766. {
  767. name = GetParameterName(parameter.ParameterName);
  768. }
  769. return name;
  770. }
  771. private static List<string> GetParametersNames(IEnumerable<IDataParameter> parameters)
  772. {
  773. var columns = new List<string>();
  774. if (parameters != null)
  775. {
  776. foreach (var parameter in parameters)
  777. {
  778. var name = GetParameterName(parameter);
  779. var isblank = TextUtility.IsBlank(name);
  780. if (isblank) continue;
  781. columns.Add(name);
  782. }
  783. }
  784. return columns;
  785. }
  786. private static string GenerateInsertStatement(string table, List<string> columns)
  787. {
  788. var result = TextUtility.EmptyString;
  789. var vtable = TextUtility.AntiInject(table, 255);
  790. if (columns != null && !TextUtility.IsBlank(vtable))
  791. {
  792. var count = 0;
  793. var names = new List<string>();
  794. var values = new List<string>();
  795. foreach (var column in columns)
  796. {
  797. //names.Add(TextGenerator.Merge("[", column, "]"));
  798. names.Add(TextUtility.Merge(column));
  799. values.Add("@" + column);
  800. count += 1;
  801. }
  802. var text = new StringBuilder();
  803. if (count > 0)
  804. {
  805. text.Append("insert into [", vtable, "](", string.Join(", ", names), ") ");
  806. text.Append("values(", string.Join(", ", values), "); ");
  807. }
  808. result = text.ToString();
  809. }
  810. return result;
  811. }
  812. private static string GenerateUpdateStatement(string table, string key, List<string> columns)
  813. {
  814. var result = TextUtility.EmptyString;
  815. var vtable = TextUtility.AntiInject(table, 255);
  816. var vkey = TextUtility.AntiInject(key, 255);
  817. if (columns != null && !TextUtility.IsBlank(vtable) && !TextUtility.IsBlank(vkey))
  818. {
  819. var items = new List<string>();
  820. foreach (var column in columns)
  821. {
  822. items.Add(TextUtility.Merge("[", column, "]=@", column));
  823. }
  824. if (items.Count > 0)
  825. {
  826. result = TextUtility.Merge("update [", vtable, "] set ", string.Join(", ", items), " where [_key]='", vkey, "'; ");
  827. }
  828. }
  829. return result;
  830. }
  831. /// <summary>生成 INSERT INTO 语句。表名必须有效,无有效参数时将获取空结果。</summary>
  832. /// <exception cref="System.ArgumentException"></exception>
  833. /// <exception cref="System.ArgumentNullException"></exception>
  834. public static string GenerateInsertStatement(string table, IEnumerable<IDataParameter> parameters)
  835. {
  836. if (table == null) throw new ArgumentNullException(nameof(table));
  837. var tableName = TextUtility.AntiInject(table, 255);
  838. if (TextUtility.IsBlank(tableName)) throw new ArgumentException("表名无效。", nameof(table));
  839. var vcolumns = GetParametersNames(parameters);
  840. if (vcolumns.Count < 1) return TextUtility.EmptyString;
  841. return GenerateInsertStatement(tableName, vcolumns);
  842. }
  843. /// <summary>生成 UPDATE 语句,键字段名为“_key”。表名必须有效,键值必须有效,无有效参数时将获取空结果。</summary>
  844. /// <exception cref="System.ArgumentException"></exception>
  845. /// <exception cref="System.ArgumentNullException"></exception>
  846. public static string GenerateUpdateStatement(string table, string key, IEnumerable<IDataParameter> parameters)
  847. {
  848. if (table == null) throw new ArgumentNullException(nameof(table));
  849. var t = TextUtility.AntiInject(table, 255);
  850. if (TextUtility.IsBlank(t)) throw new ArgumentException("表名无效。", nameof(table));
  851. if (key == null) throw new ArgumentNullException("argKey");
  852. var k = TextUtility.AntiInject(key, 255);
  853. if (TextUtility.IsBlank(k)) throw new ArgumentException("键值无效。", nameof(table));
  854. var columes = GetParametersNames(parameters);
  855. if (columes.Count < 1) return TextUtility.EmptyString;
  856. return GenerateUpdateStatement(t, k, columes);
  857. }
  858. #endregion
  859. }
  860. }
  861. #endif