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.

986 lines
36 KiB

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