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.

820 lines
30 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
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
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
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
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
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. /* 2021.11.07 */
  2. using Apewer;
  3. using Apewer.Source;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Data;
  7. using System.Data.Common;
  8. using System.Net;
  9. using System.Text;
  10. using static Apewer.Source.OrmHelper;
  11. using System.Data.SqlClient;
  12. #if NETFRAMEWORK
  13. using System.Data.Sql;
  14. #endif
  15. namespace Apewer.Source
  16. {
  17. /// <summary></summary>
  18. [Serializable]
  19. public class SqlClient : IDbClient
  20. {
  21. #region 变量、构造函数
  22. private Timeout _timeout = null;
  23. private string _connectionstring = "";
  24. /// <summary>获取或设置日志记录。</summary>
  25. public Logger Logger { get; set; }
  26. /// <summary>超时设定。</summary>
  27. public Timeout Timeout { get => _timeout; }
  28. /// <summary>使用连接字符串创建数据库连接实例。</summary>
  29. public SqlClient(string connectionString, Timeout timeout = null)
  30. {
  31. _timeout = timeout ?? Timeout.Default;
  32. _connectionstring = connectionString ?? "";
  33. }
  34. /// <summary>使用连接凭据创建数据库连接实例。</summary>
  35. public SqlClient(string address, string store, string user, string pass, Timeout timeout = null)
  36. {
  37. if (timeout == null) timeout = Timeout.Default;
  38. var a = address ?? "";
  39. var s = store ?? "";
  40. var u = user ?? "";
  41. var p = pass ?? "";
  42. var cs = $"data source = {a}; initial catalog = {s}; ";
  43. if (string.IsNullOrEmpty(u)) cs += "integrated security = sspi; ";
  44. else
  45. {
  46. cs += $"user id = {u}; ";
  47. if (!string.IsNullOrEmpty(p)) cs += $"password = {p}; ";
  48. }
  49. cs += $"connection timeout = {timeout.Connect}; ";
  50. _timeout = timeout ?? Timeout.Default;
  51. _connectionstring = cs;
  52. }
  53. #endregion
  54. #region Ado - Connection
  55. private SqlConnection _db = null;
  56. /// <summary>连接字符串。</summary>
  57. public string ConnectionString { get => _connectionstring; }
  58. /// <summary>获取当前的 SqlConnection 对象。</summary>
  59. public IDbConnection Connection { get => _db; }
  60. /// <summary>数据库是否已经连接。</summary>
  61. public bool Online
  62. {
  63. get
  64. {
  65. if (_db == null) return false;
  66. return (_db.State == ConnectionState.Open);
  67. }
  68. }
  69. /// <summary>连接数据库,若未连接则尝试连接,获取连接成功的状态。</summary>
  70. public string Connect()
  71. {
  72. if (_db == null)
  73. {
  74. _db = new SqlConnection();
  75. _db.ConnectionString = _connectionstring;
  76. }
  77. else
  78. {
  79. if (_db.State == ConnectionState.Open) return null;
  80. }
  81. try
  82. {
  83. _db.Open();
  84. switch (_db.State)
  85. {
  86. case ConnectionState.Open: return null;
  87. default: return $"连接失败,当前处于 {_db.State} 状态。";
  88. }
  89. }
  90. catch (Exception ex)
  91. {
  92. Logger.Error(nameof(SqlClient), "Connection", ex, _db.ConnectionString);
  93. Close();
  94. return ex.Message;
  95. }
  96. }
  97. /// <summary>关闭连接,并释放对象所占用的系统资源。</summary>
  98. public void Close()
  99. {
  100. if (_db != null)
  101. {
  102. if (_transaction != null)
  103. {
  104. if (_autocommit) Commit();
  105. else Rollback();
  106. }
  107. _db.Close();
  108. _db.Dispose();
  109. _db = null;
  110. }
  111. }
  112. /// <summary>关闭连接,释放对象所占用的系统资源,并清除连接信息。</summary>
  113. public void Dispose() => Close();
  114. #endregion
  115. #region Ado - Transaction
  116. private IDbTransaction _transaction = null;
  117. private bool _autocommit = false;
  118. /// <summary>启动事务。</summary>
  119. public string Begin(bool commit = true) => Begin(commit, null);
  120. /// <summary>启动事务。</summary>
  121. public string Begin(bool commit, Class<IsolationLevel> isolation)
  122. {
  123. var connect = Connect();
  124. if (connect.NotEmpty()) return connect;
  125. if (_transaction != null) return "存在已启动的事务,无法再次启动。";
  126. try
  127. {
  128. _transaction = isolation ? _db.BeginTransaction(isolation.Value) : _db.BeginTransaction();
  129. _autocommit = commit;
  130. return null;
  131. }
  132. catch (Exception ex)
  133. {
  134. Logger.Error(nameof(SqlClient), "Begin", ex.Message());
  135. return ex.Message();
  136. }
  137. }
  138. /// <summary>提交事务。</summary>
  139. public string Commit()
  140. {
  141. if (_transaction == null) return "事务不存在。";
  142. try
  143. {
  144. _transaction.Commit();
  145. RuntimeUtility.Dispose(_transaction);
  146. _transaction = null;
  147. return null;
  148. }
  149. catch (Exception ex)
  150. {
  151. RuntimeUtility.Dispose(_transaction);
  152. _transaction = null;
  153. Logger.Error(nameof(SqlClient), "Commit", ex.Message());
  154. return ex.Message();
  155. }
  156. }
  157. /// <summary>从挂起状态回滚事务。</summary>
  158. public string Rollback()
  159. {
  160. if (_transaction == null) return "事务不存在。";
  161. try
  162. {
  163. _transaction.Rollback();
  164. RuntimeUtility.Dispose(_transaction);
  165. _transaction = null;
  166. return null;
  167. }
  168. catch (Exception ex)
  169. {
  170. RuntimeUtility.Dispose(_transaction);
  171. _transaction = null;
  172. Logger.Error(nameof(SqlClient), "Rollback", ex.Message);
  173. return ex.Message();
  174. }
  175. }
  176. #endregion
  177. #region Ado - SQL
  178. /// <summary>查询。</summary>
  179. public IQuery Query(string sql) => Query(sql, null);
  180. /// <summary>查询。</summary>
  181. public IQuery Query(string sql, IEnumerable<IDataParameter> parameters)
  182. {
  183. if (TextUtility.IsBlank(sql)) return Example.InvalidQueryStatement;
  184. var connected = Connect();
  185. if (connected.NotEmpty()) return new Query(false, connected);
  186. try
  187. {
  188. using (var command = new SqlCommand())
  189. {
  190. command.Connection = _db;
  191. command.CommandTimeout = _timeout.Query;
  192. command.CommandText = sql;
  193. if (parameters != null)
  194. {
  195. foreach (var parameter in parameters)
  196. {
  197. if (parameter != null) command.Parameters.Add(parameter);
  198. }
  199. }
  200. using (var ds = new DataSet())
  201. {
  202. using (var da = new SqlDataAdapter(sql, _db))
  203. {
  204. var name = "table_" + Guid.NewGuid().ToString("n");
  205. da.Fill(ds, name);
  206. var table = ds.Tables[name];
  207. return new Query(table, true);
  208. }
  209. }
  210. }
  211. }
  212. catch (Exception exception)
  213. {
  214. Logger.Error(nameof(SqlClient), "Query", exception, sql);
  215. return new Query(exception);
  216. }
  217. }
  218. /// <summary>执行。</summary>
  219. public IExecute Execute(string sql) => Execute(sql, null);
  220. /// <summary>执行单条 Transact-SQL 语句,并加入参数。</summary>
  221. public IExecute Execute(string sql, IEnumerable<IDataParameter> parameters)
  222. {
  223. if (TextUtility.IsBlank(sql)) return Example.InvalidExecuteStatement;
  224. var connected = Connect();
  225. if (connected.NotEmpty()) return new Execute(false, connected);
  226. var inTransaction = _transaction != null;
  227. if (!inTransaction) Begin();
  228. try
  229. {
  230. using (var command = new SqlCommand())
  231. {
  232. command.Connection = _db;
  233. command.Transaction = (SqlTransaction)_transaction;
  234. command.CommandTimeout = _timeout.Execute;
  235. command.CommandText = sql;
  236. if (parameters != null)
  237. {
  238. foreach (var parameter in parameters)
  239. {
  240. if (parameter != null) command.Parameters.Add(parameter);
  241. }
  242. }
  243. var rows = command.ExecuteNonQuery();
  244. if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
  245. return new Execute(true, rows);
  246. }
  247. }
  248. catch (Exception exception)
  249. {
  250. Logger.Error(nameof(SqlClient), "Execute", exception, sql);
  251. if (!inTransaction) Rollback();
  252. return new Execute(exception);
  253. }
  254. }
  255. #endregion
  256. #region ORM
  257. /// <summary>查询数据库中的所有表名。</summary>
  258. public string[] TableNames()
  259. {
  260. var list = new List<string>();
  261. if (Connect().IsEmpty())
  262. {
  263. var sql = "select [name] from [sysobjects] where [type] = 'u' order by [name]; ";
  264. var query = (Query)Query(sql);
  265. for (int r = 0; r < query.Rows; r++)
  266. {
  267. var cell = query.Text(r, 0);
  268. if (TextUtility.IsBlank(cell)) continue;
  269. list.Add(cell);
  270. }
  271. query.Dispose();
  272. }
  273. return list.ToArray();
  274. }
  275. /// <summary>查询数据库实例中的所有数据库名。</summary>
  276. public string[] StoreNames()
  277. {
  278. var list = new List<string>();
  279. if (Connect().IsEmpty())
  280. {
  281. var sql = "select [name] from [master]..[sysdatabases] order by [name]; ";
  282. var query = (Query)Query(sql);
  283. for (int r = 0; r < query.Rows; r++)
  284. {
  285. var cell = query.Text(r, 0);
  286. if (TextUtility.IsBlank(cell)) continue;
  287. if (cell == "master") continue;
  288. if (cell == "model") continue;
  289. if (cell == "msdb") continue;
  290. if (cell == "tempdb") continue;
  291. list.Add(cell);
  292. }
  293. query.Dispose();
  294. }
  295. return list.ToArray();
  296. }
  297. /// <summary>查询表中的所有列名。</summary>
  298. public string[] ColumnNames(string tableName)
  299. {
  300. var list = new List<string>();
  301. if (Connect().IsEmpty())
  302. {
  303. var table = TextUtility.AntiInject(tableName);
  304. var sql = TextUtility.Merge("select [name] from [syscolumns] where [id] = object_id('", table, "'); ");
  305. var query = (Query)Query(sql);
  306. for (int r = 0; r < query.Rows; r++)
  307. {
  308. var cell = query.Text(r, 0);
  309. if (TextUtility.IsBlank(cell)) continue;
  310. list.Add(cell);
  311. }
  312. query.Dispose();
  313. }
  314. return list.ToArray();
  315. }
  316. static string XType(int xtype)
  317. {
  318. switch (xtype)
  319. {
  320. case 34: return "image";
  321. case 35: return "text";
  322. case 36: return "uniqueidentifier";
  323. case 48: return "tinyint";
  324. case 52: return "smallint";
  325. case 56: return "int";
  326. case 58: return "smalldatetime";
  327. case 59: return "real";
  328. case 60: return "money";
  329. case 61: return "datetime";
  330. case 62: return "float";
  331. case 98: return "sql_variant";
  332. case 99: return "ntext";
  333. case 104: return "bit";
  334. case 106: return "decimal";
  335. case 108: return "numeric";
  336. case 122: return "smallmoney";
  337. case 127: return "bigint";
  338. case 165: return "varbinary";
  339. case 167: return "varchar";
  340. case 173: return "binary";
  341. case 175: return "char";
  342. case 189: return "timestamp";
  343. case 231: return "nvarchar";
  344. case 239: return "nchar";
  345. case 241: return "xml";
  346. }
  347. return null;
  348. }
  349. /// <summary>获取列信息。</summary>
  350. public ColumnInfo[] ColumnsInfo(string tableName)
  351. {
  352. if (tableName.IsEmpty()) throw new ArgumentNullException(nameof(tableName));
  353. var sql = $"select name, xtype, length from syscolumns where id = object_id('{tableName}') ";
  354. using (var query = Query(sql))
  355. {
  356. var ab = new ArrayBuilder<ColumnInfo>();
  357. for (var i = 0; i < query.Rows; i++)
  358. {
  359. var info = new ColumnInfo();
  360. info.Name = query.Text(i, "name");
  361. info.Type = XType(query.Int32(i, "xtype"));
  362. info.Length = query.Int32(i, "length");
  363. ab.Add(info);
  364. }
  365. return ab.Export();
  366. }
  367. }
  368. /// <summary>创建表,当表不存在时创建表,当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。</summary>
  369. public string Initialize<T>() where T : class, new() => Initialize(typeof(T));
  370. /// <summary>创建表,当表不存在时创建表,当现存表中缺少模型中属性对应的列时增加列。成功时返回空字符串,发生异常时返回异常信息。</summary>
  371. public string Initialize(Type model)
  372. {
  373. var structure = TableStructure.Parse(model);
  374. if (structure == null) return "无法解析记录模型。";
  375. // 连接数据库。
  376. var connect = Connect();
  377. if (connect.NotEmpty()) return connect;
  378. // 检查现存表。
  379. var exists = false;
  380. var tables = TableNames();
  381. if (tables.Length > 0)
  382. {
  383. var lower = structure.Name.ToLower();
  384. foreach (var table in tables)
  385. {
  386. if (TextUtility.IsBlank(table)) continue;
  387. if (table.ToLower() == lower)
  388. {
  389. exists = true;
  390. break;
  391. }
  392. }
  393. }
  394. if (exists)
  395. {
  396. // 获取已存在的列名。
  397. var columns = ColumnNames(structure.Name);
  398. if (columns.Length > 0)
  399. {
  400. var lower = new List<string>();
  401. foreach (var column in columns)
  402. {
  403. if (TextUtility.IsBlank(column)) continue;
  404. lower.Add(column.ToLower());
  405. }
  406. columns = lower.ToArray();
  407. }
  408. // 增加列。
  409. foreach (var column in structure.Columns)
  410. {
  411. // 检查 Independent 特性。
  412. if (structure.Independent && column.Independent) continue;
  413. // 去重。
  414. var lower = column.Field.ToLower();
  415. if (columns.Contains(lower)) continue;
  416. var type = Declaration(column);
  417. if (string.IsNullOrEmpty(type)) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  418. var sql = TextUtility.Merge("alter table [", structure.Name, "] add ", type, "; ");
  419. var execute = Execute(sql);
  420. if (execute.Success == false) return execute.Message;
  421. }
  422. return TextUtility.Empty;
  423. }
  424. else
  425. {
  426. var sqlcolumns = new List<string>();
  427. foreach (var column in structure.Columns)
  428. {
  429. // 检查 Independent 特性。
  430. if (structure.Independent && column.Independent) continue;
  431. var type = Declaration(column);
  432. if (!column.Independent && column.Property.Name == "Key") type = type + " primary key";
  433. if (string.IsNullOrEmpty(type)) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  434. sqlcolumns.Add(type);
  435. }
  436. var sql = TextUtility.Merge("create table [", structure.Name, "](", string.Join(", ", sqlcolumns.ToArray()), "); ");
  437. var execute = Execute(sql);
  438. if (execute.Success) return TextUtility.Empty;
  439. return execute.Message;
  440. }
  441. }
  442. /// <summary>插入记录。返回错误信息。</summary>
  443. public string Insert(object record, string table = null)
  444. {
  445. if (record == null) return "参数无效。";
  446. FixProperties(record);
  447. var structure = TableStructure.Parse(record.GetType());
  448. if (structure == null) return "无法解析记录模型。";
  449. if (string.IsNullOrEmpty(table)) table = structure.Name;
  450. if (string.IsNullOrEmpty(table)) return "表名称无效。";
  451. var ps = structure.CreateParameters(record, Parameter);
  452. var psc = ps.Length;
  453. if (psc < 1) return "数据模型不包含字段。";
  454. var names = new List<string>(psc);
  455. var values = new List<string>(psc);
  456. foreach (var column in ps)
  457. {
  458. //names.Add(TextGenerator.Merge("[", column, "]"));
  459. names.Add(TextUtility.Merge(column));
  460. values.Add("@" + column);
  461. }
  462. var sb = new StringBuilder();
  463. sb.Append("insert into [", table, "](", string.Join(", ", names.ToArray()), ") ");
  464. sb.Append("values(", string.Join(", ", values.ToArray()), "); ");
  465. var sql = sb.ToString();
  466. var execute = Execute(sql, ps);
  467. if (execute.Success) return TextUtility.Empty;
  468. return execute.Message;
  469. }
  470. /// <summary>更新记录,实体中的 Key 属性不被更新。返回错误信息。</summary>
  471. /// <remarks>无法更新带有 Independent 特性的模型(缺少 Key 属性)。</remarks>
  472. public string Update(IRecord record, string table = null)
  473. {
  474. if (record == null) return "参数无效。";
  475. FixProperties(record);
  476. SetUpdated(record);
  477. var structure = TableStructure.Parse(record.GetType());
  478. if (structure == null) return "无法解析记录模型。";
  479. if (structure.Independent) return "无法更新带有 Independent 特性的模型。";
  480. if (string.IsNullOrEmpty(table)) table = structure.Name;
  481. if (string.IsNullOrEmpty(table)) return "表名称无效。";
  482. var ps = structure.CreateParameters(record, Parameter, "_key");
  483. var psc = ps.Length;
  484. if (psc < 1) return "数据模型不包含字段。";
  485. var items = new List<string>();
  486. foreach (var p in ps)
  487. {
  488. var pn = p.ParameterName;
  489. items.Add(TextUtility.Merge("[", pn, "] = @", pn));
  490. }
  491. var key = record.Key.SafeKey();
  492. var sql = TextUtility.Merge("update [", table, "] set ", string.Join(", ", items.ToArray()), " where [_key]='", key, "'; ");
  493. var execute = Execute(sql, ps);
  494. if (execute.Success) return TextUtility.Empty;
  495. return execute.Message;
  496. }
  497. /// <summary>获取按指定语句查询到的所有记录。</summary>
  498. public Result<object[]> Query(Type model, string sql) => OrmHelper.Query(this, model, sql);
  499. /// <summary>获取按指定语句查询到的所有记录。</summary>
  500. public Result<T[]> Query<T>(string sql) where T : class, new()
  501. {
  502. var query = Query(sql);
  503. if (!query.Success) return new Result<T[]>(query.Message);
  504. var records = query.Fill<T>();
  505. query.Dispose();
  506. var result = new Result<T[]>(records);
  507. return result;
  508. }
  509. /// <summary>获取记录。</summary>
  510. public Result<object[]> Query(Type model, long flag = 0) => OrmHelper.Query(this, model, (tn) =>
  511. {
  512. if (flag == 0) return $"select * from [{tn}]; ";
  513. return $"select * from [{tn}] where _flag={flag}; ";
  514. });
  515. /// <summary>获取记录。</summary>
  516. public Result<T[]> Query<T>(long flag = 0) where T : class, IRecord, new() => OrmHelper.Query<T>(this, (tn) =>
  517. {
  518. if (flag == 0) return $"select * from [{tn}]; ";
  519. return $"select * from [{tn}] where _flag={flag}; ";
  520. });
  521. /// <summary>获取具有指定 Key 的记录。</summary>
  522. public Result<object> Get(Type model, string key, long flag = 0) => OrmHelper.Get(this, model, key, (tn, sk) =>
  523. {
  524. if (flag == 0) return $"select top 1 * from [{tn}] _key='{sk}'; ";
  525. return $"select top 1 * from [{tn}] where _key='{sk}' and _key='{sk}'; ";
  526. });
  527. /// <summary>获取具有指定 Key 的记录。</summary>
  528. public Result<T> Get<T>(string key, long flag = 0) where T : class, IRecord, new() => OrmHelper.Get<T>(this, key, (tn, sk) =>
  529. {
  530. if (flag == 0) return $"select top 1 * from [{tn}] _key='{sk}'; ";
  531. return $"select top 1 * from [{tn}] where _key='{sk}' and _key='{sk}'; ";
  532. });
  533. /// <summary>查询有效的 Key 值。</summary>
  534. public Result<string[]> Keys(Type model, long flag = 0) => OrmHelper.Keys(this, model, (tn) =>
  535. {
  536. if (flag == 0) return $"select _key from [{tn}]; ";
  537. return $"select _key from [{tn}] where _flag={flag}; ";
  538. });
  539. /// <summary>查询有效的 Key 值。</summary>
  540. public Result<string[]> Keys<T>(long flag = 0) where T : class, IRecord, new() => Keys(typeof(T), flag);
  541. #endregion
  542. #region public static
  543. #if NET20 || NET40
  544. /// <summary>枚举本地网络中服务器的名称。</summary>
  545. public static SqlServerSource[] EnumerateServer()
  546. {
  547. var list = new List<SqlServerSource>();
  548. // 表中列名:ServerName、InstanceName、IsClustered、Version。
  549. using (var query = new Query(SqlDataSourceEnumerator.Instance.GetDataSources()))
  550. {
  551. for (int i = 0; i < query.Rows; i++)
  552. {
  553. var item = new SqlServerSource();
  554. item.ServerName = query.Text(i, "ServerName");
  555. list.Add(item);
  556. }
  557. }
  558. return list.ToArray();
  559. }
  560. #endif
  561. /// <summary>指定的连接凭据是否符合连接要求,默认指定 master 数据库。</summary>
  562. public static bool Proven(string address, string user, string pass) => Proven(address, "master", user, pass);
  563. /// <summary>指定的连接凭据是否符合连接要求。</summary>
  564. public static bool Proven(string address, string store, string user, string pass)
  565. {
  566. var a = string.IsNullOrEmpty(address);
  567. var s = string.IsNullOrEmpty(store);
  568. var u = string.IsNullOrEmpty(user);
  569. var p = string.IsNullOrEmpty(pass);
  570. if (a) return false;
  571. if (s) return false;
  572. if (u && !p) return false;
  573. return true;
  574. }
  575. /// <summary>创建参数。</summary>
  576. /// <exception cref="ArgumentNullException"></exception>
  577. /// <exception cref="InvalidOperationException"></exception>
  578. static SqlParameter Parameter(Parameter parameter)
  579. {
  580. if (parameter == null) throw new InvalidOperationException("参数无效。");
  581. return Parameter(parameter.Name, parameter.Type, parameter.Size, parameter.Value);
  582. }
  583. /// <summary>创建参数。</summary>
  584. public static SqlParameter Parameter(string name, ColumnType type, int size, object value)
  585. {
  586. var vname = TextUtility.Trim(name);
  587. if (TextUtility.IsBlank(vname)) return null;
  588. var vtype = SqlDbType.BigInt;
  589. switch (type)
  590. {
  591. case ColumnType.Bytes:
  592. vtype = SqlDbType.Image;
  593. break;
  594. case ColumnType.Integer:
  595. vtype = SqlDbType.BigInt;
  596. break;
  597. case ColumnType.Float:
  598. vtype = SqlDbType.Float;
  599. break;
  600. case ColumnType.DateTime:
  601. vtype = SqlDbType.DateTime;
  602. break;
  603. case ColumnType.VarChar:
  604. case ColumnType.VarChar191:
  605. case ColumnType.VarCharMax:
  606. vtype = SqlDbType.VarChar;
  607. break;
  608. case ColumnType.NVarChar:
  609. case ColumnType.NVarChar191:
  610. case ColumnType.NVarCharMax:
  611. vtype = SqlDbType.NVarChar;
  612. break;
  613. case ColumnType.Text:
  614. vtype = SqlDbType.Text;
  615. break;
  616. case ColumnType.NText:
  617. vtype = SqlDbType.NText;
  618. break;
  619. default:
  620. throw new InvalidOperationException(TextUtility.Merge("类型 ", type.ToString(), " 不受支持。"));
  621. }
  622. var vsize = size;
  623. switch (type)
  624. {
  625. case ColumnType.VarChar:
  626. vsize = NumberUtility.Restrict(vsize, 0, 8000);
  627. break;
  628. case ColumnType.NVarChar:
  629. vsize = NumberUtility.Restrict(vsize, 0, 4000);
  630. break;
  631. case ColumnType.VarChar191:
  632. case ColumnType.NVarChar191:
  633. vsize = NumberUtility.Restrict(vsize, 0, 191);
  634. break;
  635. default:
  636. vsize = 0;
  637. break;
  638. }
  639. var vvalue = value;
  640. if (vvalue is string && vvalue != null && vsize > 0)
  641. {
  642. vvalue = TextUtility.Left((string)vvalue, vsize);
  643. }
  644. var parameter = new SqlParameter();
  645. parameter.ParameterName = vname;
  646. parameter.SqlDbType = vtype;
  647. parameter.Value = vvalue;
  648. if (vsize > 0) parameter.Size = vsize;
  649. return parameter;
  650. }
  651. /// <summary>创建参数。</summary>
  652. public static SqlParameter Parameter(string name, SqlDbType type, int size, object value)
  653. {
  654. if (value is string && value != null && size > 0)
  655. {
  656. value = TextUtility.Left((string)value, (int)size);
  657. }
  658. var p = new SqlParameter();
  659. p.ParameterName = name ?? "";
  660. p.SqlDbType = type;
  661. p.Size = size;
  662. p.Value = value;
  663. return p;
  664. }
  665. /// <summary>创建参数。</summary>
  666. public static SqlParameter Parameter(string name, SqlDbType type, object value)
  667. {
  668. var p = new SqlParameter();
  669. p.ParameterName = name ?? "";
  670. p.SqlDbType = type;
  671. p.Value = value;
  672. return p;
  673. }
  674. static string Declaration(ColumnAttribute column)
  675. {
  676. var type = TextUtility.Empty;
  677. var vcolumn = column;
  678. var length = Math.Max(0, vcolumn.Length);
  679. switch (vcolumn.Type)
  680. {
  681. case ColumnType.Integer:
  682. type = "bigint";
  683. break;
  684. case ColumnType.Float:
  685. type = "float";
  686. break;
  687. case ColumnType.Bytes:
  688. type = "image";
  689. break;
  690. case ColumnType.DateTime:
  691. type = "datetime";
  692. break;
  693. case ColumnType.VarChar:
  694. type = TextUtility.Merge("varchar(", Math.Min(8000, length).ToString(), ")");
  695. break;
  696. case ColumnType.VarChar191:
  697. type = TextUtility.Merge("varchar(191)");
  698. break;
  699. case ColumnType.VarCharMax:
  700. type = TextUtility.Merge("varchar(max)");
  701. break;
  702. case ColumnType.Text:
  703. type = TextUtility.Merge("text");
  704. break;
  705. case ColumnType.NVarChar:
  706. type = TextUtility.Merge("nvarchar(", Math.Min(4000, length).ToString(), ")");
  707. break;
  708. case ColumnType.NVarChar191:
  709. type = TextUtility.Merge("nvarchar(191)");
  710. break;
  711. case ColumnType.NVarCharMax:
  712. type = TextUtility.Merge("nvarchar(max)");
  713. break;
  714. case ColumnType.NText:
  715. type = TextUtility.Merge("ntext");
  716. break;
  717. default:
  718. return TextUtility.Empty;
  719. }
  720. return TextUtility.Merge("[", vcolumn.Field, "] ", type);
  721. }
  722. #endregion
  723. }
  724. }