Sqlite类库,基于framework 4.0框架

前端之家收集整理的这篇文章主要介绍了Sqlite类库,基于framework 4.0框架前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
  1. //
  2. // Copyright (c) 2009-2010 Krueger Systems,Inc.
  3. //
  4.  
  5. using System;
  6. using System.Runtime.InteropServices;
  7. using System.Collections.Generic;
  8. using System.Reflection;
  9. using System.Linq;
  10. using System.Linq.Expressions;
  11.  
  12. namespace sqlite
  13. {
  14. public class sqliteException : System.Exception
  15. {
  16. public sqlite3.Result Result { get; private set; }
  17.  
  18. protected sqliteException (sqlite3.Result r,string message) : base(message)
  19. {
  20. Result = r;
  21. }
  22.  
  23. public static sqliteException New (sqlite3.Result r,string message)
  24. {
  25. return new sqliteException (r,message);
  26. }
  27. }
  28.  
  29. /// <summary>
  30. /// Represents an open connection to a sqlite database.
  31. /// </summary>
  32. public class sqliteConnection : IDisposable
  33. {
  34. private bool _open;
  35. private TimeSpan _busyTimeout;
  36. private Dictionary<string,TableMapping> _mappings = null;
  37. private Dictionary<string,TableMapping> _tables = null;
  38. private System.Diagnostics.Stopwatch _sw;
  39. private long _elapsedMilliseconds = 0;
  40.  
  41. /// <summary>
  42. /// 句柄
  43. /// </summary>
  44. /// <value>The handle.</value>
  45. public IntPtr Handle { get; private set; }
  46.  
  47. /// <summary>
  48. /// Gets the Database path.
  49. /// </summary>
  50. /// <value>The Database path.</value>
  51. public string DatabasePath { get; private set; }
  52.  
  53. public bool TimeExecution { get; set; }
  54.  
  55. public bool Trace { get; set; }
  56.  
  57. /// <summary>
  58. /// Constructs a new sqliteConnection and opens a sqlite database specified by databasePath.
  59. /// </summary>
  60. /// <param name="databasePath">
  61. /// Specifies the path to the database file.
  62. /// </param>
  63. public sqliteConnection (string databasePath)
  64. {
  65. DatabasePath = databasePath;
  66. IntPtr _handle;
  67. var r = sqlite3.Open (DatabasePath,out _handle);
  68. Handle = _handle;
  69. if (r != sqlite3.Result.OK) {
  70. throw sqliteException.New (r,"Could not open database file: " + DatabasePath);
  71. }
  72. _open = true;
  73. BusyTimeout = TimeSpan.FromSeconds (0.1);
  74. }
  75.  
  76. static sqliteConnection ()
  77. {
  78. if (_preserveDuringLinkMagic) {
  79. var ti = new TableInfo ();
  80. ti.name = "magic";
  81. }
  82. }
  83.  
  84. /// <summary>
  85. /// Used to list some code that we want the MonoTouch linker
  86. /// to see,but that we never want to actually execute.
  87. /// </summary>
  88. static bool _preserveDuringLinkMagic = false;
  89.  
  90. /// <summary>
  91. /// Sets a busy handler to sleep the specified amount of time when a table is locked.
  92. /// The handler will sleep multiple times until a total time of <see cref="BusyTimeout"/> has accumulated.
  93. /// </summary>
  94. public TimeSpan BusyTimeout {
  95. get { return _busyTimeout; }
  96. set {
  97. _busyTimeout = value;
  98. if (Handle != IntPtr.Zero) {
  99. sqlite3.BusyTimeout (Handle,(int)_busyTimeout.TotalMilliseconds);
  100. }
  101. }
  102. }
  103.  
  104. /// <summary>
  105. /// Returns the mappings from types to tables that the connection
  106. /// currently understands.
  107. /// </summary>
  108. public IEnumerable<TableMapping> TableMappings {
  109. get {
  110. if (_tables == null) {
  111. return Enumerable.Empty<TableMapping> ();
  112. } else {
  113. return _tables.Values;
  114. }
  115. }
  116. }
  117.  
  118. /// <summary>
  119. /// Retrieves the mapping that is automatically generated for the given type.
  120. /// </summary>
  121. /// <param name="type">
  122. /// The type whose mapping to the database is returned.
  123. /// </param>
  124. /// <returns>
  125. /// The mapping represents the schema of the columns of the database and contains
  126. /// methods to set and get properties of objects.
  127. /// </returns>
  128. public TableMapping GetMapping (Type type)
  129. {
  130. if (_mappings == null) {
  131. _mappings = new Dictionary<string,TableMapping> ();
  132. }
  133. TableMapping map;
  134. if (!_mappings.TryGetValue (type.FullName,out map)) {
  135. map = new TableMapping (type);
  136. _mappings [type.FullName] = map;
  137. }
  138. return map;
  139. }
  140.  
  141. /// <summary>
  142. /// Executes a "create table if not exists" on the database. It also
  143. /// creates any specified indexes on the columns of the table. It uses
  144. /// a schema automatically generated from the specified type. You can
  145. /// later access this schema by calling GetMapping.
  146. /// </summary>
  147. /// <returns>
  148. /// The number of entries added to the database schema.
  149. /// </returns>
  150. public int CreateTable<T> ()
  151. {
  152. var ty = typeof(T);
  153. if (_tables == null) {
  154. _tables = new Dictionary<string,TableMapping> ();
  155. }
  156. TableMapping map;
  157. if (!_tables.TryGetValue (ty.FullName,out map)) {
  158. map = GetMapping (ty);
  159. _tables.Add (ty.FullName,map);
  160. }
  161.  
  162. var query = "create table \"" + map.TableName + "\"\n(\n";
  163. var decls = map.Columns.Select (p => Orm.sqlDecl (p));
  164. var decl = string.Join (",\n",decls.ToArray ());
  165. query += decl;
  166. query += "\n)";
  167. var count = 0;
  168. try {
  169. Execute (query);
  170. count = 1;
  171. }
  172. catch (sqliteException) {
  173. }
  174. if (count == 0) {
  175. // Table already exists,migrate it
  176. MigrateTable (map);
  177. }
  178.  
  179. foreach (var p in map.Columns.Where (x => x.IsIndexed)) {
  180. var indexName = map.TableName + "_" + p.Name;
  181. var q = string.Format ("create index if not exists \"{0}\" on \"{1}\"(\"{2}\")",indexName,map.TableName,p.Name);
  182. count += Execute (q);
  183. }
  184. return count;
  185. }
  186.  
  187. class TableInfo
  188. {
  189. public int cid { get; set; }
  190.  
  191. public string name { get; set; }
  192.  
  193. public string type { get; set; }
  194.  
  195. public int notnull { get; set; }
  196.  
  197. public string dflt_value { get; set; }
  198.  
  199. public int pk { get; set; }
  200. }
  201.  
  202. void MigrateTable (TableMapping map)
  203. {
  204. var query = "pragma table_info(\"" + map.TableName + "\")";
  205. var existingCols = Query<TableInfo> (query);
  206.  
  207. var toBeAdded = new List<TableMapping.Column> ();
  208. foreach (var p in map.Columns) {
  209. var found = false;
  210. foreach (var c in existingCols) {
  211. found = p.Name == c.name;
  212. if (found)
  213. break;
  214. }
  215. if (!found) {
  216. toBeAdded.Add (p);
  217. }
  218. }
  219. foreach (var p in toBeAdded) {
  220. var addCol = "alter table \"" + map.TableName + "\" add column " + Orm.sqlDecl (p);
  221. Execute (addCol);
  222. }
  223. }
  224.  
  225. /// <summary>
  226. /// Creates a new sqliteCommand given the command text with arguments. Place a '?'
  227. /// in the command text for each of the arguments.
  228. /// </summary>
  229. /// <param name="cmdText">
  230. /// The fully escaped sql.
  231. /// </param>
  232. /// <param name="args">
  233. /// Arguments to substitute for the occurences of '?' in the command text.
  234. /// </param>
  235. /// <returns>
  236. /// A <see cref="sqliteCommand"/>
  237. /// </returns>
  238. public sqliteCommand CreateCommand (string cmdText,params object[] ps)
  239. {
  240. if (!_open) {
  241. throw sqliteException.New (sqlite3.Result.Error,"Cannot create commands from unopened database");
  242. } else {
  243. var cmd = new sqliteCommand (this);
  244. cmd.CommandText = cmdText;
  245. foreach (var o in ps) {
  246. cmd.Bind (o);
  247. }
  248. return cmd;
  249. }
  250. }
  251.  
  252. /// <summary>
  253. /// Creates a sqliteCommand given the command text (sql) with arguments. Place a '?'
  254. /// in the command text for each of the arguments and then executes that command.
  255. /// Use this method instead of Query when you don't expect rows back. Such cases include
  256. /// INSERTs,UPDATEs,and DELETEs.
  257. /// You can set the Trace or TimeExecution properties of the connection
  258. /// to profile execution.
  259. /// </summary>
  260. /// <param name="query">
  261. /// The fully escaped sql.
  262. /// </param>
  263. /// <param name="args">
  264. /// Arguments to substitute for the occurences of '?' in the query.
  265. /// </param>
  266. /// <returns>
  267. /// The number of rows modified in the database as a result of this execution.
  268. /// </returns>
  269. public int Execute (string query,params object[] args)
  270. {
  271. var cmd = CreateCommand (query,args);
  272. if (TimeExecution) {
  273. if (_sw == null) {
  274. _sw = new System.Diagnostics.Stopwatch ();
  275. }
  276. _sw.Reset ();
  277. _sw.Start ();
  278. }
  279. int r = cmd.ExecuteNonQuery ();
  280. if (TimeExecution) {
  281. _sw.Stop ();
  282. _elapsedMilliseconds += _sw.ElapsedMilliseconds;
  283. Console.WriteLine ("Finished in {0} ms ({1:0.0} s total)",_sw.ElapsedMilliseconds,_elapsedMilliseconds / 1000.0);
  284. }
  285. return r;
  286. }
  287.  
  288. /// <summary>
  289. /// Creates a sqliteCommand given the command text (sql) with arguments. Place a '?'
  290. /// in the command text for each of the arguments and then executes that command.
  291. /// It returns each row of the result using the mapping automatically generated for
  292. /// the given type.
  293. /// </summary>
  294. /// <param name="query">
  295. /// The fully escaped sql.
  296. /// </param>
  297. /// <param name="args">
  298. /// Arguments to substitute for the occurences of '?' in the query.
  299. /// </param>
  300. /// <returns>
  301. /// An enumerable with one result for each row returned by the query.
  302. /// </returns>
  303. public List<T> Query<T> (string query,params object[] args) where T : new()
  304. {
  305. var cmd = CreateCommand (query,args);
  306. return cmd.ExecuteQuery<T> ();
  307. }
  308.  
  309. /// <summary>
  310. /// Creates a sqliteCommand given the command text (sql) with arguments. Place a '?'
  311. /// in the command text for each of the arguments and then executes that command.
  312. /// It returns each row of the result using the specified mapping. This function is
  313. /// only used by libraries in order to query the database via introspection. It is
  314. /// normally not used.
  315. /// </summary>
  316. /// <param name="map">
  317. /// A <see cref="TableMapping"/> to use to convert the resulting rows
  318. /// into objects.
  319. /// </param>
  320. /// <param name="query">
  321. /// The fully escaped sql.
  322. /// </param>
  323. /// <param name="args">
  324. /// Arguments to substitute for the occurences of '?' in the query.
  325. /// </param>
  326. /// <returns>
  327. /// An enumerable with one result for each row returned by the query.
  328. /// </returns>
  329. public List<object> Query (TableMapping map,string query,args);
  330. return cmd.ExecuteQuery<object> (map);
  331. }
  332.  
  333. /// <summary>
  334. /// Returns a queryable interface to the table represented by the given type.
  335. /// </summary>
  336. /// <returns>
  337. /// A queryable object that is able to translate Where,OrderBy,and Take
  338. /// queries into native sql.
  339. /// </returns>
  340. public TableQuery<T> Table<T> () where T : new()
  341. {
  342. return new TableQuery<T> (this);
  343. }
  344.  
  345. /// <summary>
  346. /// Attempts to retrieve an object with the given primary key from the table
  347. /// associated with the specified type. Use of this method requires that
  348. /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
  349. /// </summary>
  350. /// <param name="pk">
  351. /// The primary key.
  352. /// </param>
  353. /// <returns>
  354. /// The object with the given primary key. Throws a not found exception
  355. /// if the object is not found.
  356. /// </returns>
  357. public T Get<T> (object pk) where T : new()
  358. {
  359. var map = GetMapping (typeof(T));
  360. string query = string.Format ("select * from \"{0}\" where \"{1}\" = ?",map.PK.Name);
  361. return Query<T> (query,pk).First ();
  362. }
  363.  
  364. /// <summary>
  365. /// Whether <see cref="BeginTransaction"/> has been called and the database is waiting for a <see cref="Commit"/>.
  366. /// </summary>
  367. public bool IsInTransaction { get; private set; }
  368.  
  369. /// <summary>
  370. /// Begins a new transaction. Call <see cref="Commit"/> to end the transaction.
  371. /// </summary>
  372. public void BeginTransaction ()
  373. {
  374. if (!IsInTransaction) {
  375. Execute ("begin transaction");
  376. IsInTransaction = true;
  377. }
  378. }
  379.  
  380. /// <summary>
  381. /// Rolls back the transaction that was begun by <see cref="BeginTransaction"/>.
  382. /// </summary>
  383. public void Rollback ()
  384. {
  385. if (IsInTransaction) {
  386. Execute ("rollback");
  387. IsInTransaction = false;
  388. }
  389. }
  390.  
  391. /// <summary>
  392. /// Commits the transaction that was begun by <see cref="BeginTransaction"/>.
  393. /// </summary>
  394. public void Commit ()
  395. {
  396. if (IsInTransaction) {
  397. Execute ("commit");
  398. IsInTransaction = false;
  399. }
  400. }
  401.  
  402. /// <summary>
  403. /// Executes <param name="action"> within a transaction and automatically rollsback the transaction
  404. /// if an exception occurs. The exception is rethrown.
  405. /// </summary>
  406. /// <param name="action">
  407. /// The <see cref="Action"/> to perform within a transaction. <param name="action"> can contain any number
  408. /// of operations on the connection but should never call <see cref="BeginTransaction"/>,/// <see cref="Rollback"/>,or <see cref="Commit"/>.
  409. /// </param>
  410. public void RunInTransaction (Action action)
  411. {
  412. if (IsInTransaction) {
  413. throw new InvalidOperationException ("The connection must not already be in a transaction when RunInTransaction is called");
  414. }
  415. try {
  416. BeginTransaction ();
  417. action ();
  418. Commit ();
  419. } catch (Exception) {
  420. Rollback ();
  421. throw;
  422. }
  423. }
  424.  
  425. /// <summary>
  426. /// Inserts all specified objects.
  427. /// </summary>
  428. /// <param name="objects">
  429. /// An <see cref="IEnumerable"/> of the objects to insert.
  430. /// </param>
  431. /// <returns>
  432. /// The number of rows added to the table.
  433. /// </returns>
  434. public int InsertAll (System.Collections.IEnumerable objects)
  435. {
  436. BeginTransaction ();
  437. var c = 0;
  438. foreach (var r in objects) {
  439. c += Insert (r);
  440. }
  441. Commit ();
  442. return c;
  443. }
  444.  
  445. /// <summary>
  446. /// Inserts the given object and retrieves its
  447. /// auto incremented primary key if it has one.
  448. /// </summary>
  449. /// <param name="obj">
  450. /// The object to insert.
  451. /// </param>
  452. /// <returns>
  453. /// The number of rows added to the table.
  454. /// </returns>
  455. public int Insert (object obj)
  456. {
  457. if (obj == null) {
  458. return 0;
  459. }
  460. return Insert (obj,"",obj.GetType ());
  461. }
  462.  
  463. public int Insert (object obj,Type objType)
  464. {
  465. return Insert (obj,objType);
  466. }
  467.  
  468. public int Insert (object obj,string extra)
  469. {
  470. if (obj == null) {
  471. return 0;
  472. }
  473. return Insert (obj,extra,obj.GetType ());
  474. }
  475.  
  476. /// <summary>
  477. /// Inserts the given object and retrieves its
  478. /// auto incremented primary key if it has one.
  479. /// </summary>
  480. /// <param name="obj">
  481. /// The object to insert.
  482. /// </param>
  483. /// <param name="extra">
  484. /// Literal sql code that gets placed into the command. INSERT {extra} INTO ...
  485. /// </param>
  486. /// <returns>
  487. /// The number of rows added to the table.
  488. /// </returns>
  489. public int Insert (object obj,string extra,Type objType)
  490. {
  491. if (obj == null || objType == null) {
  492. return 0;
  493. }
  494. var map = GetMapping (objType);
  495. var cols = map.InsertColumns;
  496. var vals = new object[cols.Length];
  497. for (var i = 0; i < vals.Length; i++) {
  498. vals [i] = cols [i].GetValue (obj);
  499. }
  500. var insertCmd = map.GetInsertCommand (this,extra);
  501. var count = insertCmd.ExecuteNonQuery (vals);
  502. if (map.HasAutoIncPK) {
  503. var id = sqlite3.LastInsertRowid (Handle);
  504. map.SetAutoIncPK (obj,id);
  505. }
  506. return count;
  507. }
  508.  
  509. /// <summary>
  510. /// Updates all of the columns of a table using the specified object
  511. /// except for its primary key.
  512. /// The object is required to have a primary key.
  513. /// </summary>
  514. /// <param name="obj">
  515. /// The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
  516. /// </param>
  517. /// <returns>
  518. /// The number of rows updated.
  519. /// </returns>
  520. public int Update (object obj)
  521. {
  522. if (obj == null) {
  523. return 0;
  524. }
  525. return Update (obj,obj.GetType ());
  526. }
  527.  
  528. public int Update (object obj,Type objType)
  529. {
  530. if (obj == null || objType == null) {
  531. return 0;
  532. }
  533. var map = GetMapping (objType);
  534. var pk = map.PK;
  535. if (pk == null) {
  536. throw new NotSupportedException ("Cannot update " + map.TableName + ": it has no PK");
  537. }
  538. var cols = from p in map.Columns
  539. where p != pk
  540. select p;
  541. var vals = from c in cols
  542. select c.GetValue (obj);
  543. var ps = new List<object> (vals);
  544. ps.Add (pk.GetValue (obj));
  545. var q = string.Format ("update \"{0}\" set {1} where {2} = ? ",string.Join (",",(from c in cols
  546. select "\"" + c.Name + "\" = ? ").ToArray ()),pk.Name);
  547. return Execute (q,ps.ToArray ());
  548. }
  549.  
  550. /// <summary>
  551. /// Deletes the given object from the database using its primary key.
  552. /// </summary>
  553. /// <param name="obj">
  554. /// The object to delete. It must have a primary key designated using the PrimaryKeyAttribute.
  555. /// </param>
  556. /// <returns>
  557. /// The number of rows deleted.
  558. /// </returns>
  559. public int Delete<T> (T obj)
  560. {
  561. var map = GetMapping (obj.GetType ());
  562. var pk = map.PK;
  563. if (pk == null) {
  564. throw new NotSupportedException ("Cannot delete " + map.TableName + ": it has no PK");
  565. }
  566. var q = string.Format ("delete from \"{0}\" where \"{1}\" = ?",pk.GetValue (obj));
  567. }
  568.  
  569. public void Dispose ()
  570. {
  571. Close ();
  572. }
  573.  
  574. public void Close ()
  575. {
  576. if (_open && Handle != IntPtr.Zero) {
  577. sqlite3.Close (Handle);
  578. Handle = IntPtr.Zero;
  579. _open = false;
  580. }
  581. }
  582. }
  583.  
  584. /*继承于Attribute的类,表示特性类,它在使用时候,如果它的类名字是以Attribute结尾了,则被调用时候类名上面的Attribute可以不用谢*/
  585.  
  586. public class PrimaryKeyAttribute : Attribute
  587. {
  588. }
  589.  
  590. public class AutoIncrementAttribute : Attribute
  591. {
  592. }
  593.  
  594. public class IndexedAttribute : Attribute
  595. {
  596. }
  597.  
  598. public class IgnoreAttribute : Attribute
  599. {
  600. }
  601.  
  602. public class MaxLengthAttribute : Attribute
  603. {
  604. public int Value { get; private set; }
  605.  
  606. public MaxLengthAttribute (int length)
  607. {
  608. Value = length;
  609. }
  610. }
  611.  
  612. public class CollationAttribute: Attribute
  613. {
  614. public string Value { get; private set; }
  615.  
  616. public CollationAttribute (string collation)
  617. {
  618. Value = collation;
  619. }
  620. }
  621.  
  622. public class TableMapping
  623. {
  624. public Type MappedType { get; private set; }
  625.  
  626. public string TableName { get; private set; }
  627.  
  628. public Column[] Columns { get; private set; }
  629.  
  630. public Column PK { get; private set; }
  631.  
  632. Column _autoPk = null;
  633. Column[] _insertColumns = null;
  634. string _insertsql = null;
  635.  
  636. public TableMapping (Type type)
  637. {
  638. MappedType = type;
  639. TableName = MappedType.Name;
  640. var props = MappedType.GetProperties (BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
  641. var cols = new List<Column> ();
  642. foreach (var p in props) {
  643. var ignore = p.GetCustomAttributes (typeof(IgnoreAttribute),true).Length > 0;
  644. if (p.CanWrite && !ignore) {
  645. cols.Add (new PropColumn (p));
  646. }
  647. }
  648. Columns = cols.ToArray ();
  649. foreach (var c in Columns) {
  650. if (c.IsAutoInc && c.IsPK) {
  651. _autoPk = c;
  652. }
  653. if (c.IsPK) {
  654. PK = c;
  655. }
  656. }
  657. HasAutoIncPK = _autoPk != null;
  658. }
  659.  
  660. public bool HasAutoIncPK { get; private set; }
  661.  
  662. public void SetAutoIncPK (object obj,long id)
  663. {
  664. if (_autoPk != null) {
  665. _autoPk.SetValue (obj,Convert.ChangeType (id,_autoPk.ColumnType));
  666. }
  667. }
  668.  
  669. public Column[] InsertColumns {
  670. get {
  671. if (_insertColumns == null) {
  672. _insertColumns = Columns.Where (c => !c.IsAutoInc).ToArray ();
  673. }
  674. return _insertColumns;
  675. }
  676. }
  677.  
  678. public Column FindColumn (string name)
  679. {
  680. var exact = Columns.Where (c => c.Name == name).FirstOrDefault ();
  681. return exact;
  682. }
  683.  
  684. public string Insertsql (string extra)
  685. {
  686. if (_insertsql == null) {
  687. var cols = InsertColumns;
  688. _insertsql = string.Format ("insert {3} into \"{0}\"({1}) values ({2})",TableName,(from c in cols
  689. select "\"" + c.Name + "\"").ToArray ()),(from c in cols
  690. select "?").ToArray ()),extra);
  691. }
  692. return _insertsql;
  693. }
  694.  
  695. PreparedsqlLiteInsertCommand _insertCommand;
  696. string _insertCommandExtra = null;
  697.  
  698. public PreparedsqlLiteInsertCommand GetInsertCommand (sqliteConnection conn,string extra)
  699. {
  700. if (_insertCommand == null || _insertCommandExtra != extra) {
  701. var insertsql = Insertsql (extra);
  702. _insertCommand = new PreparedsqlLiteInsertCommand (conn);
  703. _insertCommand.CommandText = insertsql;
  704. _insertCommandExtra = extra;
  705. }
  706. return _insertCommand;
  707. }
  708.  
  709. public abstract class Column
  710. {
  711. public string Name { get; protected set; }
  712.  
  713. public Type ColumnType { get; protected set; }
  714.  
  715. public string Collation { get; protected set; }
  716.  
  717. public bool IsAutoInc { get; protected set; }
  718.  
  719. public bool IsPK { get; protected set; }
  720.  
  721. public bool IsIndexed { get; protected set; }
  722.  
  723. public bool IsNullable { get; protected set; }
  724.  
  725. public int MaxStringLength { get; protected set; }
  726.  
  727. public abstract void SetValue (object obj,object val);
  728.  
  729. public abstract object GetValue (object obj);
  730. }
  731.  
  732. public class PropColumn : Column
  733. {
  734. PropertyInfo _prop;
  735.  
  736. public PropColumn (PropertyInfo prop)
  737. {
  738. _prop = prop;
  739. Name = prop.Name;
  740. //If this type is Nullable<T> then Nullable.GetUnderlyingType returns the T,otherwise it returns null,so get the the actual type instead
  741. ColumnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
  742. Collation = Orm.Collation (prop);
  743. IsAutoInc = Orm.IsAutoInc (prop);
  744. IsPK = Orm.IsPK (prop);
  745. IsIndexed = Orm.IsIndexed (prop);
  746. IsNullable = !IsPK;
  747. MaxStringLength = Orm.MaxStringLength (prop);
  748. }
  749.  
  750. public override void SetValue (object obj,object val)
  751. {
  752. _prop.SetValue (obj,val,null);
  753. }
  754.  
  755. public override object GetValue (object obj)
  756. {
  757. return _prop.GetValue (obj,null);
  758. }
  759. }
  760. }
  761.  
  762. public static class Orm
  763. {
  764. public const int DefaultMaxStringLength = 140;
  765.  
  766. public static string sqlDecl (TableMapping.Column p)
  767. {
  768. string decl = "\"" + p.Name + "\" " + sqlType (p) + " ";
  769. if (p.IsPK) {
  770. decl += "primary key ";
  771. }
  772. if (p.IsAutoInc) {
  773. decl += "autoincrement ";
  774. }
  775. if (!p.IsNullable) {
  776. decl += "not null ";
  777. }
  778. if (!string.IsNullOrEmpty (p.Collation)) {
  779. decl += "collate " + p.Collation + " ";
  780. }
  781. return decl;
  782. }
  783.  
  784. public static string sqlType (TableMapping.Column p)
  785. {
  786. var clrType = p.ColumnType;
  787. if (clrType == typeof(Boolean) || clrType == typeof(Byte) || clrType == typeof(UInt16) || clrType == typeof(SByte) || clrType == typeof(Int16) || clrType == typeof(Int32)) {
  788. return "integer";
  789. } else if (clrType == typeof(UInt32) || clrType == typeof(Int64)) {
  790. return "bigint";
  791. } else if (clrType == typeof(Single) || clrType == typeof(Double) || clrType == typeof(Decimal)) {
  792. return "float";
  793. } else if (clrType == typeof(String)) {
  794. int len = p.MaxStringLength;
  795. return "varchar(" + len + ")";
  796. } else if (clrType == typeof(DateTime)) {
  797. return "datetime";
  798. } else if (clrType.IsEnum) {
  799. return "integer";
  800. } else if (clrType == typeof(byte[])) {
  801. return "blob";
  802. } else {
  803. throw new NotSupportedException ("Don't know about " + clrType);
  804. }
  805. }
  806.  
  807. public static bool IsPK (MemberInfo p)
  808. {
  809. var attrs = p.GetCustomAttributes (typeof(PrimaryKeyAttribute),true);
  810. return attrs.Length > 0;
  811. }
  812.  
  813. public static string Collation (MemberInfo p)
  814. {
  815. var attrs = p.GetCustomAttributes (typeof(CollationAttribute),true);
  816. if (attrs.Length > 0) {
  817. return ((CollationAttribute)attrs [0]).Value;
  818. } else {
  819. return string.Empty;
  820. }
  821. }
  822.  
  823. public static bool IsAutoInc (MemberInfo p)
  824. {
  825. var attrs = p.GetCustomAttributes (typeof(AutoIncrementAttribute),true);
  826. return attrs.Length > 0;
  827. }
  828.  
  829. public static bool IsIndexed (MemberInfo p)
  830. {
  831. var attrs = p.GetCustomAttributes (typeof(IndexedAttribute),true);
  832. return attrs.Length > 0;
  833. }
  834.  
  835. public static int MaxStringLength (PropertyInfo p)
  836. {
  837. var attrs = p.GetCustomAttributes (typeof(MaxLengthAttribute),true);
  838. if (attrs.Length > 0) {
  839. return ((MaxLengthAttribute)attrs [0]).Value;
  840. } else {
  841. return DefaultMaxStringLength;
  842. }
  843. }
  844. }
  845.  
  846. public class sqliteCommand
  847. {
  848. sqliteConnection _conn;
  849. private List<Binding> _bindings;
  850.  
  851. public string CommandText { get; set; }
  852.  
  853. internal sqliteCommand (sqliteConnection conn)
  854. {
  855. _conn = conn;
  856. _bindings = new List<Binding> ();
  857. CommandText = "";
  858. }
  859.  
  860. public int ExecuteNonQuery ()
  861. {
  862. if (_conn.Trace) {
  863. Console.WriteLine ("Executing: " + this);
  864. }
  865. var r = sqlite3.Result.OK;
  866. var stmt = Prepare ();
  867. r = sqlite3.Step (stmt);
  868. Finalize (stmt);
  869. if (r == sqlite3.Result.Done) {
  870. int rowsAffected = sqlite3.Changes (_conn.Handle);
  871. return rowsAffected;
  872. } else if (r == sqlite3.Result.Error) {
  873. string msg = sqlite3.GetErrmsg (_conn.Handle);
  874. throw sqliteException.New (r,msg);
  875. } else {
  876. throw sqliteException.New (r,r.ToString ());
  877. }
  878. }
  879.  
  880. public List<T> ExecuteQuery<T> () where T : new()
  881. {
  882. return ExecuteQuery<T> (_conn.GetMapping (typeof(T)));
  883. }
  884.  
  885. public List<T> ExecuteQuery<T> (TableMapping map)
  886. {
  887. if (_conn.Trace) {
  888. Console.WriteLine ("Executing Query: " + this);
  889. }
  890. var r = new List<T> ();
  891. var stmt = Prepare ();
  892. var cols = new TableMapping.Column[sqlite3.ColumnCount (stmt)];
  893. for (int i = 0; i < cols.Length; i++) {
  894. var name = Marshal.PtrToStringUni (sqlite3.ColumnName16 (stmt,i));
  895. cols [i] = map.FindColumn (name);
  896. }
  897. while (sqlite3.Step (stmt) == sqlite3.Result.Row) {
  898. var obj = Activator.CreateInstance (map.MappedType);
  899. for (int i = 0; i < cols.Length; i++) {
  900. if (cols [i] == null)
  901. continue;
  902. var colType = sqlite3.ColumnType (stmt,i);
  903. var val = ReadCol (stmt,i,colType,cols [i].ColumnType);
  904. cols [i].SetValue (obj,val);
  905. }
  906. r.Add ((T)obj);
  907. }
  908. Finalize (stmt);
  909. return r;
  910. }
  911.  
  912. public T ExecuteScalar<T> ()
  913. {
  914. if (_conn.Trace) {
  915. Console.WriteLine ("Executing Query: " + this);
  916. }
  917. T val = default(T);
  918. var stmt = Prepare ();
  919. if (sqlite3.Step (stmt) == sqlite3.Result.Row) {
  920. var colType = sqlite3.ColumnType (stmt,0);
  921. val = (T)ReadCol (stmt,typeof(T));
  922. }
  923. Finalize (stmt);
  924. return val;
  925. }
  926.  
  927. public void Bind (string name,object val)
  928. {
  929. _bindings.Add (new Binding {
  930. Name = name,Value = val
  931. });
  932. }
  933.  
  934. public void Bind (object val)
  935. {
  936. Bind (null,val);
  937. }
  938.  
  939. public override string ToString ()
  940. {
  941. var parts = new string[1 + _bindings.Count];
  942. parts [0] = CommandText;
  943. var i = 1;
  944. foreach (var b in _bindings) {
  945. parts [i] = string.Format (" {0}: {1}",i - 1,b.Value);
  946. i++;
  947. }
  948. return string.Join (Environment.NewLine,parts);
  949. }
  950.  
  951. IntPtr Prepare ()
  952. {
  953. var stmt = sqlite3.Prepare2 (_conn.Handle,CommandText);
  954. BindAll (stmt);
  955. return stmt;
  956. }
  957.  
  958. void Finalize (IntPtr stmt)
  959. {
  960. sqlite3.Finalize (stmt);
  961. }
  962.  
  963. void BindAll (IntPtr stmt)
  964. {
  965. int nextIdx = 1;
  966. foreach (var b in _bindings) {
  967. if (b.Name != null) {
  968. b.Index = sqlite3.BindParameterIndex (stmt,b.Name);
  969. } else {
  970. b.Index = nextIdx++;
  971. }
  972. }
  973. foreach (var b in _bindings) {
  974. BindParameter (stmt,b.Index,b.Value);
  975. }
  976. }
  977.  
  978. internal static IntPtr NegativePointer = new IntPtr (-1);
  979.  
  980. internal static void BindParameter (IntPtr stmt,int index,object value)
  981. {
  982. if (value == null) {
  983. sqlite3.BindNull (stmt,index);
  984. } else {
  985. if (value is Int32) {
  986. sqlite3.BindInt (stmt,index,(int)value);
  987. } else if (value is String) {
  988. sqlite3.BindText (stmt,(string)value,-1,NegativePointer);
  989. } else if (value is Byte || value is UInt16 || value is SByte || value is Int16) {
  990. sqlite3.BindInt (stmt,Convert.ToInt32 (value));
  991. } else if (value is Boolean) {
  992. sqlite3.BindInt (stmt,(bool)value ? 1 : 0);
  993. } else if (value is UInt32 || value is Int64) {
  994. sqlite3.BindInt64 (stmt,Convert.ToInt64 (value));
  995. } else if (value is Single || value is Double || value is Decimal) {
  996. sqlite3.BindDouble (stmt,Convert.ToDouble (value));
  997. } else if (value is DateTime) {
  998. sqlite3.BindText (stmt,((DateTime)value).ToString ("yyyy-MM-dd HH:mm:ss"),NegativePointer);
  999. } else if (value.GetType ().IsEnum) {
  1000. sqlite3.BindInt (stmt,Convert.ToInt32 (value));
  1001. } else if (value is byte[]) {
  1002. sqlite3.BindBlob (stmt,(byte[])value,((byte[])value).Length,NegativePointer);
  1003. } else {
  1004. throw new NotSupportedException ("Cannot store type: " + value.GetType ());
  1005. }
  1006. }
  1007. }
  1008.  
  1009. class Binding
  1010. {
  1011. public string Name { get; set; }
  1012.  
  1013. public object Value { get; set; }
  1014.  
  1015. public int Index { get; set; }
  1016. }
  1017.  
  1018. object ReadCol (IntPtr stmt,sqlite3.ColType type,Type clrType)
  1019. {
  1020. if (type == sqlite3.ColType.Null) {
  1021. return null;
  1022. } else {
  1023. if (clrType == typeof(String)) {
  1024. return sqlite3.ColumnString (stmt,index);
  1025. } else if (clrType == typeof(Int32)) {
  1026. return (int)sqlite3.ColumnInt (stmt,index);
  1027. } else if (clrType == typeof(Boolean)) {
  1028. return sqlite3.ColumnInt (stmt,index) == 1;
  1029. } else if (clrType == typeof(double)) {
  1030. return sqlite3.ColumnDouble (stmt,index);
  1031. } else if (clrType == typeof(float)) {
  1032. return (float)sqlite3.ColumnDouble (stmt,index);
  1033. } else if (clrType == typeof(DateTime)) {
  1034. var text = sqlite3.ColumnString (stmt,index);
  1035. return DateTime.Parse (text);
  1036. } else if (clrType.IsEnum) {
  1037. return sqlite3.ColumnInt (stmt,index);
  1038. } else if (clrType == typeof(Int64)) {
  1039. return sqlite3.ColumnInt64 (stmt,index);
  1040. } else if (clrType == typeof(UInt32)) {
  1041. return (uint)sqlite3.ColumnInt64 (stmt,index);
  1042. } else if (clrType == typeof(decimal)) {
  1043. return (decimal)sqlite3.ColumnDouble (stmt,index);
  1044. } else if (clrType == typeof(Byte)) {
  1045. return (byte)sqlite3.ColumnInt (stmt,index);
  1046. } else if (clrType == typeof(UInt16)) {
  1047. return (ushort)sqlite3.ColumnInt (stmt,index);
  1048. } else if (clrType == typeof(Int16)) {
  1049. return (short)sqlite3.ColumnInt (stmt,index);
  1050. } else if (clrType == typeof(sbyte)) {
  1051. return (sbyte)sqlite3.ColumnInt (stmt,index);
  1052. } else if (clrType == typeof(byte[])) {
  1053. return sqlite3.ColumnByteArray (stmt,index);
  1054. } else {
  1055. throw new NotSupportedException ("Don't know how to read " + clrType);
  1056. }
  1057. }
  1058. }
  1059. }
  1060.  
  1061. /// <summary>
  1062. /// Since the insert never changed,we only need to prepare once.
  1063. /// </summary>
  1064. public class PreparedsqlLiteInsertCommand : IDisposable
  1065. {
  1066. public bool Initialized { get; set; }
  1067.  
  1068. protected sqliteConnection Connection { get; set; }
  1069.  
  1070. public string CommandText { get; set; }
  1071.  
  1072. protected IntPtr Statement { get; set; }
  1073.  
  1074. internal PreparedsqlLiteInsertCommand (sqliteConnection conn)
  1075. {
  1076. Connection = conn;
  1077. }
  1078.  
  1079. public int ExecuteNonQuery (object[] source)
  1080. {
  1081. if (Connection.Trace) {
  1082. Console.WriteLine ("Executing: " + CommandText);
  1083. }
  1084.  
  1085. var r = sqlite3.Result.OK;
  1086.  
  1087. if (!Initialized) {
  1088. Statement = Prepare ();
  1089. Initialized = true;
  1090. }
  1091.  
  1092. //bind the values.
  1093. if (source != null) {
  1094. for (int i = 0; i < source.Length; i++) {
  1095. sqliteCommand.BindParameter (Statement,i + 1,source [i]);
  1096. }
  1097. }
  1098. r = sqlite3.Step (Statement);
  1099.  
  1100. if (r == sqlite3.Result.Done) {
  1101. int rowsAffected = sqlite3.Changes (Connection.Handle);
  1102. sqlite3.Reset (Statement);
  1103. return rowsAffected;
  1104. } else if (r == sqlite3.Result.Error) {
  1105. string msg = sqlite3.GetErrmsg (Connection.Handle);
  1106. sqlite3.Reset (Statement);
  1107. throw sqliteException.New (r,msg);
  1108. } else {
  1109. sqlite3.Reset (Statement);
  1110. throw sqliteException.New (r,r.ToString ());
  1111. }
  1112. }
  1113.  
  1114. protected virtual IntPtr Prepare ()
  1115. {
  1116. var stmt = sqlite3.Prepare2 (Connection.Handle,CommandText);
  1117. return stmt;
  1118. }
  1119.  
  1120. public void Dispose ()
  1121. {
  1122. Dispose (true);
  1123. GC.SuppressFinalize (this);
  1124. }
  1125.  
  1126. private void Dispose (bool disposing)
  1127. {
  1128. if (Statement != IntPtr.Zero) {
  1129. try {
  1130. sqlite3.Finalize (Statement);
  1131. } finally {
  1132. Statement = IntPtr.Zero;
  1133. Connection = null;
  1134. }
  1135. }
  1136. }
  1137.  
  1138. ~PreparedsqlLiteInsertCommand ()
  1139. {
  1140. Dispose (false);
  1141. }
  1142. }
  1143.  
  1144. public class TableQuery<T> : IEnumerable<T> where T : new()
  1145. {
  1146. public sqliteConnection Connection { get; private set; }
  1147.  
  1148. public TableMapping Table { get; private set; }
  1149.  
  1150. Expression _where;
  1151. List<Ordering> _orderBys;
  1152. int? _limit;
  1153. int? _offset;
  1154.  
  1155. class Ordering
  1156. {
  1157. public string ColumnName { get; set; }
  1158.  
  1159. public bool Ascending { get; set; }
  1160. }
  1161.  
  1162. TableQuery (sqliteConnection conn,TableMapping table)
  1163. {
  1164. Connection = conn;
  1165. Table = table;
  1166. }
  1167.  
  1168. public TableQuery (sqliteConnection conn)
  1169. {
  1170. Connection = conn;
  1171. Table = Connection.GetMapping (typeof(T));
  1172. }
  1173.  
  1174. public TableQuery<T> Clone ()
  1175. {
  1176. var q = new TableQuery<T> (Connection,Table);
  1177. q._where = _where;
  1178. if (_orderBys != null) {
  1179. q._orderBys = new List<Ordering> (_orderBys);
  1180. }
  1181. q._limit = _limit;
  1182. q._offset = _offset;
  1183. return q;
  1184. }
  1185.  
  1186. public TableQuery<T> Where (Expression<Func<T,bool>> predExpr)
  1187. {
  1188. if (predExpr.NodeType == ExpressionType.Lambda) {
  1189. var lambda = (LambdaExpression)predExpr;
  1190. var pred = lambda.Body;
  1191. var q = Clone ();
  1192. q.AddWhere (pred);
  1193. return q;
  1194. } else {
  1195. throw new NotSupportedException ("Must be a predicate");
  1196. }
  1197. }
  1198.  
  1199. public TableQuery<T> Take (int n)
  1200. {
  1201. var q = Clone ();
  1202. q._limit = n;
  1203. return q;
  1204. }
  1205.  
  1206. public TableQuery<T> Skip (int n)
  1207. {
  1208. var q = Clone ();
  1209. q._offset = n;
  1210. return q;
  1211. }
  1212.  
  1213. public TableQuery<T> OrderBy<U> (Expression<Func<T,U>> orderExpr)
  1214. {
  1215. return AddOrderBy<U> (orderExpr,true);
  1216. }
  1217.  
  1218. public TableQuery<T> OrderByDescending<U> (Expression<Func<T,false);
  1219. }
  1220.  
  1221. private TableQuery<T> AddOrderBy<U> (Expression<Func<T,U>> orderExpr,bool asc)
  1222. {
  1223. if (orderExpr.NodeType == ExpressionType.Lambda) {
  1224. var lambda = (LambdaExpression)orderExpr;
  1225. var mem = lambda.Body as MemberExpression;
  1226. if (mem != null && (mem.Expression.NodeType == ExpressionType.Parameter)) {
  1227. var q = Clone ();
  1228. if (q._orderBys == null) {
  1229. q._orderBys = new List<Ordering> ();
  1230. }
  1231. q._orderBys.Add (new Ordering {
  1232. ColumnName = mem.Member.Name,Ascending = asc
  1233. });
  1234. return q;
  1235. } else {
  1236. throw new NotSupportedException ("Order By does not support: " + orderExpr);
  1237. }
  1238. } else {
  1239. throw new NotSupportedException ("Must be a predicate");
  1240. }
  1241. }
  1242.  
  1243. private void AddWhere (Expression pred)
  1244. {
  1245. if (_where == null) {
  1246. _where = pred;
  1247. } else {
  1248. _where = Expression.AndAlso (_where,pred);
  1249. }
  1250. }
  1251.  
  1252. private sqliteCommand GenerateCommand (string selectionList)
  1253. {
  1254. var cmdText = "select " + selectionList + " from \"" + Table.TableName + "\"";
  1255. var args = new List<object> ();
  1256. if (_where != null) {
  1257. var w = CompileExpr (_where,args);
  1258. cmdText += " where " + w.CommandText;
  1259. }
  1260. if ((_orderBys != null) && (_orderBys.Count > 0)) {
  1261. var t = string.Join (",_orderBys.Select (o => "\"" + o.ColumnName + "\"" + (o.Ascending ? "" : " desc")).ToArray ());
  1262. cmdText += " order by " + t;
  1263. }
  1264. if (_limit.HasValue) {
  1265. cmdText += " limit " + _limit.Value;
  1266. }
  1267. if (_offset.HasValue) {
  1268. if (!_limit.HasValue) {
  1269. cmdText += " limit -1 ";
  1270. }
  1271. cmdText += " offset " + _offset.Value;
  1272. }
  1273. return Connection.CreateCommand (cmdText,args.ToArray ());
  1274. }
  1275.  
  1276. class CompileResult
  1277. {
  1278. public string CommandText { get; set; }
  1279.  
  1280. public object Value { get; set; }
  1281. }
  1282.  
  1283. private CompileResult CompileExpr (Expression expr,List<object> queryArgs)
  1284. {
  1285. if (expr == null) {
  1286. throw new NotSupportedException ("Expression is NULL");
  1287. } else if (expr is BinaryExpression) {
  1288. var bin = (BinaryExpression)expr;
  1289. var leftr = CompileExpr (bin.Left,queryArgs);
  1290. var rightr = CompileExpr (bin.Right,queryArgs);
  1291.  
  1292. //If either side is a parameter and is null,then handle the other side specially (for "is null"/"is not null")
  1293. string text;
  1294. if (leftr.CommandText == "?" && leftr.Value == null)
  1295. text = CompileNullBinaryExpression(bin,rightr);
  1296. else if (rightr.CommandText == "?" && rightr.Value == null)
  1297. text = CompileNullBinaryExpression(bin,leftr);
  1298. else
  1299. text = "(" + leftr.CommandText + " " + GetsqlName(bin) + " " + rightr.CommandText + ")";
  1300. return new CompileResult { CommandText = text };
  1301. } else if (expr.NodeType == ExpressionType.Call) {
  1302. var call = (MethodCallExpression)expr;
  1303. var args = new CompileResult[call.Arguments.Count];
  1304. for (var i = 0; i < args.Length; i++) {
  1305. args [i] = CompileExpr (call.Arguments [i],queryArgs);
  1306. }
  1307. var sqlCall = "";
  1308. if (call.Method.Name == "Like" && args.Length == 2) {
  1309. sqlCall = "(" + args [0].CommandText + " like " + args [1].CommandText + ")";
  1310. } else if (call.Method.Name == "Contains" && args.Length == 2) {
  1311. sqlCall = "(" + args [1].CommandText + " in " + args [0].CommandText + ")";
  1312. } else {
  1313. sqlCall = call.Method.Name.ToLower () + "(" + string.Join (",args.Select (a => a.CommandText).ToArray ()) + ")";
  1314. }
  1315. return new CompileResult { CommandText = sqlCall };
  1316. } else if (expr.NodeType == ExpressionType.Constant) {
  1317. var c = (ConstantExpression)expr;
  1318. queryArgs.Add (c.Value);
  1319. return new CompileResult {
  1320. CommandText = "?",Value = c.Value
  1321. };
  1322. } else if (expr.NodeType == ExpressionType.Convert) {
  1323. var u = (UnaryExpression)expr;
  1324. var ty = u.Type;
  1325. var valr = CompileExpr (u.Operand,queryArgs);
  1326. return new CompileResult {
  1327. CommandText = valr.CommandText,Value = valr.Value != null ? Convert.ChangeType (valr.Value,ty) : null
  1328. };
  1329. } else if (expr.NodeType == ExpressionType.MemberAccess) {
  1330. var mem = (MemberExpression)expr;
  1331. if (mem.Expression.NodeType == ExpressionType.Parameter) {
  1332. //
  1333. // This is a column of our table,output just the column name
  1334. //
  1335. return new CompileResult { CommandText = "\"" + mem.Member.Name + "\"" };
  1336. } else {
  1337. object obj = null;
  1338. if (mem.Expression != null) {
  1339. var r = CompileExpr (mem.Expression,queryArgs);
  1340. if (r.Value == null) {
  1341. throw new NotSupportedException ("Member access Failed to compile expression");
  1342. }
  1343. if (r.CommandText == "?") {
  1344. queryArgs.RemoveAt (queryArgs.Count - 1);
  1345. }
  1346. obj = r.Value;
  1347. }
  1348. //
  1349. // Get the member value
  1350. //
  1351. object val = null;
  1352. if (mem.Member.MemberType == MemberTypes.Property) {
  1353. var m = (PropertyInfo)mem.Member;
  1354. val = m.GetValue (obj,null);
  1355. } else if (mem.Member.MemberType == MemberTypes.Field) {
  1356. var m = (FieldInfo)mem.Member;
  1357. val = m.GetValue (obj);
  1358. } else {
  1359. throw new NotSupportedException ("MemberExpr: " + mem.Member.MemberType.ToString ());
  1360. }
  1361. //
  1362. // Work special magic for enumerables
  1363. //
  1364. if (val != null && val is System.Collections.IEnumerable && !(val is string)) {
  1365. var sb = new System.Text.StringBuilder();
  1366. sb.Append("(");
  1367. var head = "";
  1368. foreach (var a in (System.Collections.IEnumerable)val) {
  1369. queryArgs.Add(a);
  1370. sb.Append(head);
  1371. sb.Append("?");
  1372. head = ",";
  1373. }
  1374. sb.Append(")");
  1375. return new CompileResult {
  1376. CommandText = sb.ToString(),Value = val
  1377. };
  1378. }
  1379. else {
  1380. queryArgs.Add (val);
  1381. return new CompileResult {
  1382. CommandText = "?",Value = val
  1383. };
  1384. }
  1385. }
  1386. }
  1387. throw new NotSupportedException ("Cannot compile: " + expr.NodeType.ToString ());
  1388. }
  1389.  
  1390. /// <summary>
  1391. /// Compiles a BinaryExpression where one of the parameters is null.
  1392. /// </summary>
  1393. /// <param name="parameter">The non-null parameter</param>
  1394. private string CompileNullBinaryExpression(BinaryExpression expression,CompileResult parameter)
  1395. {
  1396. if (expression.NodeType == ExpressionType.Equal)
  1397. return "(" + parameter.CommandText + " is ?)";
  1398. else if (expression.NodeType == ExpressionType.NotEqual)
  1399. return "(" + parameter.CommandText + " is not ?)";
  1400. else
  1401. throw new NotSupportedException("Cannot compile Null-BinaryExpression with type " + expression.NodeType.ToString());
  1402. }
  1403.  
  1404. string GetsqlName (Expression expr)
  1405. {
  1406. var n = expr.NodeType;
  1407. if (n == ExpressionType.GreaterThan) {
  1408. return ">";
  1409. } else if (n == ExpressionType.GreaterThanOrEqual) {
  1410. return ">=";
  1411. } else if (n == ExpressionType.LessThan) {
  1412. return "<";
  1413. } else if (n == ExpressionType.LessThanOrEqual) {
  1414. return "<=";
  1415. } else if (n == ExpressionType.And) {
  1416. return "and";
  1417. } else if (n == ExpressionType.AndAlso) {
  1418. return "and";
  1419. } else if (n == ExpressionType.Or) {
  1420. return "or";
  1421. } else if (n == ExpressionType.OrElse) {
  1422. return "or";
  1423. } else if (n == ExpressionType.Equal) {
  1424. return "=";
  1425. } else if (n == ExpressionType.NotEqual) {
  1426. return "!=";
  1427. } else {
  1428. throw new System.NotSupportedException ("Cannot get sql for: " + n.ToString ());
  1429. }
  1430. }
  1431. public int Count ()
  1432. {
  1433. return GenerateCommand("count(*)").ExecuteScalar<int> ();
  1434. }
  1435.  
  1436. public IEnumerator<T> GetEnumerator ()
  1437. {
  1438. return GenerateCommand ("*").ExecuteQuery<T> ().GetEnumerator ();
  1439. }
  1440.  
  1441. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
  1442. {
  1443. return GetEnumerator ();
  1444. }
  1445. }
  1446.  
  1447. public static class sqlite3
  1448. {
  1449. public enum Result : int
  1450. {
  1451. OK = 0,Error = 1,Internal = 2,Perm = 3,Abort = 4,Busy = 5,Locked = 6,NoMem = 7,ReadOnly = 8,Interrupt = 9,IOError = 10,Corrupt = 11,NotFound = 12,TooBig = 18,Constraint = 19,Row = 100,Done = 101
  1452. }
  1453.  
  1454. public enum ConfigOption : int
  1455. {
  1456. SingleThread = 1,MultiThread = 2,Serialized = 3
  1457. }
  1458.  
  1459. [DllImport("sqlite3",EntryPoint = "sqlite3_open")]
  1460. public static extern Result Open (string filename,out IntPtr db);
  1461.  
  1462. [DllImport("sqlite3",EntryPoint = "sqlite3_close")]
  1463. public static extern Result Close (IntPtr db);
  1464.  
  1465. [DllImport("sqlite3",EntryPoint = "sqlite3_config")]
  1466. public static extern Result Config (ConfigOption option);
  1467.  
  1468. [DllImport("sqlite3",EntryPoint = "sqlite3_busy_timeout")]
  1469. public static extern Result BusyTimeout (IntPtr db,int milliseconds);
  1470.  
  1471. [DllImport("sqlite3",EntryPoint = "sqlite3_changes")]
  1472. public static extern int Changes (IntPtr db);
  1473.  
  1474. [DllImport("sqlite3",EntryPoint = "sqlite3_prepare_v2")]
  1475. public static extern Result Prepare2 (IntPtr db,string sql,int numBytes,out IntPtr stmt,IntPtr pzTail);
  1476.  
  1477. public static IntPtr Prepare2 (IntPtr db,string query)
  1478. {
  1479. IntPtr stmt;
  1480. var r = Prepare2 (db,query,query.Length,out stmt,IntPtr.Zero);
  1481. if (r != Result.OK) {
  1482. throw sqliteException.New (r,GetErrmsg (db));
  1483. }
  1484. return stmt;
  1485. }
  1486.  
  1487. [DllImport("sqlite3",EntryPoint = "sqlite3_step")]
  1488. public static extern Result Step (IntPtr stmt);
  1489.  
  1490. [DllImport("sqlite3",EntryPoint = "sqlite3_reset")]
  1491. public static extern Result Reset (IntPtr stmt);
  1492.  
  1493. [DllImport("sqlite3",EntryPoint = "sqlite3_finalize")]
  1494. public static extern Result Finalize (IntPtr stmt);
  1495.  
  1496. [DllImport("sqlite3",EntryPoint = "sqlite3_last_insert_rowid")]
  1497. public static extern long LastInsertRowid (IntPtr db);
  1498.  
  1499. [DllImport("sqlite3",EntryPoint = "sqlite3_errmsg16")]
  1500. public static extern IntPtr Errmsg (IntPtr db);
  1501.  
  1502. public static string GetErrmsg (IntPtr db)
  1503. {
  1504. return Marshal.PtrToStringUni (Errmsg (db));
  1505. }
  1506.  
  1507. [DllImport("sqlite3",EntryPoint = "sqlite3_bind_parameter_index")]
  1508. public static extern int BindParameterIndex (IntPtr stmt,string name);
  1509.  
  1510. [DllImport("sqlite3",EntryPoint = "sqlite3_bind_null")]
  1511. public static extern int BindNull (IntPtr stmt,int index);
  1512.  
  1513. [DllImport("sqlite3",EntryPoint = "sqlite3_bind_int")]
  1514. public static extern int BindInt (IntPtr stmt,int val);
  1515.  
  1516. [DllImport("sqlite3",EntryPoint = "sqlite3_bind_int64")]
  1517. public static extern int BindInt64 (IntPtr stmt,long val);
  1518.  
  1519. [DllImport("sqlite3",EntryPoint = "sqlite3_bind_double")]
  1520. public static extern int BindDouble (IntPtr stmt,double val);
  1521.  
  1522. [DllImport("sqlite3",EntryPoint = "sqlite3_bind_text")]
  1523. public static extern int BindText (IntPtr stmt,string val,int n,IntPtr free);
  1524.  
  1525. [DllImport("sqlite3",EntryPoint = "sqlite3_bind_blob")]
  1526. public static extern int BindBlob (IntPtr stmt,byte[] val,EntryPoint = "sqlite3_column_count")]
  1527. public static extern int ColumnCount (IntPtr stmt);
  1528.  
  1529. [DllImport("sqlite3",EntryPoint = "sqlite3_column_name")]
  1530. public static extern IntPtr ColumnName (IntPtr stmt,EntryPoint = "sqlite3_column_name16")]
  1531. public static extern IntPtr ColumnName16 (IntPtr stmt,EntryPoint = "sqlite3_column_type")]
  1532. public static extern ColType ColumnType (IntPtr stmt,EntryPoint = "sqlite3_column_int")]
  1533. public static extern int ColumnInt (IntPtr stmt,EntryPoint = "sqlite3_column_int64")]
  1534. public static extern long ColumnInt64 (IntPtr stmt,EntryPoint = "sqlite3_column_double")]
  1535. public static extern double ColumnDouble (IntPtr stmt,EntryPoint = "sqlite3_column_text")]
  1536. public static extern IntPtr ColumnText (IntPtr stmt,EntryPoint = "sqlite3_column_text16")]
  1537. public static extern IntPtr ColumnText16 (IntPtr stmt,EntryPoint = "sqlite3_column_blob")]
  1538. public static extern IntPtr ColumnBlob (IntPtr stmt,EntryPoint = "sqlite3_column_bytes")]
  1539. public static extern int ColumnBytes (IntPtr stmt,int index);
  1540.  
  1541. public static string ColumnString (IntPtr stmt,int index)
  1542. {
  1543. return Marshal.PtrToStringUni (sqlite3.ColumnText16 (stmt,index));
  1544. }
  1545.  
  1546. public static byte[] ColumnByteArray (IntPtr stmt,int index)
  1547. {
  1548. int length = ColumnBytes (stmt,index);
  1549. byte[] result = new byte[length];
  1550. if (length > 0)
  1551. Marshal.Copy (ColumnBlob (stmt,index),result,length);
  1552. return result;
  1553. }
  1554.  
  1555. public enum ColType : int
  1556. {
  1557. Integer = 1,Float = 2,Text = 3,Blob = 4,Null = 5
  1558. }
  1559. }
  1560. }

调用举例:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using MonoTouch.Foundation;
  5. using MonoTouch.UIKit;
  6. using System.Data;
  7. using System.IO;
  8. using sqlite;
  9.  
  10. namespace Xamarin.Screens.sqliteNet
  11. {
  12. public partial class BasicOperations : UITableViewController
  13. {
  14. protected List<Person> people = new List<Person> ();
  15. protected TableSource tableSource;
  16. #region Constructors
  17.  
  18. public BasicOperations (IntPtr handle) : base(handle) { Initialize (); }
  19. [Export("initWithCoder:")]
  20. public BasicOperations (NSCoder coder) : base(coder) { Initialize (); }
  21. public BasicOperations () : base("DataSample",null) { Initialize (); }
  22. protected void Initialize ()
  23. {
  24. this.Title = "sqlite .NET";
  25.  
  26. string dbName = "db_sqlite-net.db3";
  27. // check the database,if it doesn't exist,create it
  28. CheckAndCreateDatabase (dbName);
  29.  
  30. // create a connection to the database
  31. using (sqliteConnection db = new sqliteConnection (GetDBPath (dbName)))
  32. {
  33. // query a list of people from the db
  34. people = new List<Person> (from p in db.Table<Person> () select p);
  35. // create a new table source from our people collection
  36. tableSource = new BasicOperations.TableSource (people);
  37. // initialize the table view and set the source
  38. base.TableView = new UITableView () {
  39. Source = tableSource
  40. };
  41. }
  42. }
  43. #endregion
  44. protected string GetDBPath (string dbName)
  45. {
  46. // get a reference to the documents folder
  47. var documents = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
  48. // create the db path
  49. string db = Path.Combine (documents,dbName);
  50. return db;
  51. }
  52. // This method checks to see if the database exists,and if it doesn't,it creates
  53. // it and inserts some data
  54. protected void CheckAndCreateDatabase (string dbName)
  55. {
  56. // create a connection object. if the database doesn't exist,it will create
  57. // a blank database
  58. using(sqliteConnection db = new sqliteConnection (GetDBPath (dbName)))
  59. {
  60. // create the tables
  61. db.CreateTable<Person> ();
  62. // skip inserting data if it already exists
  63. if(db.Table<Person>().Count() > 0)
  64. return;
  65. // declare vars
  66. List<Person> people = new List<Person> ();
  67. // create a list of people that we're going to insert
  68. people.Add (new Person () { FirstName = "Peter",LastName = "Gabriel" });
  69. people.Add (new Person () { FirstName = "Thom",LastName = "Yorke" });
  70. people.Add (new Person () { FirstName = "J",LastName = "Spaceman" });
  71. people.Add (new Person () { FirstName = "Benjamin",LastName = "Gibbard" });
  72. // insert our people
  73. db.InsertAll (people);
  74. // close the connection
  75. db.Close ();
  76. }
  77. }
  78. // A simple data source for our table
  79. protected class TableSource : UITableViewSource
  80. {
  81. List<Person> items;
  82. public TableSource (List<Person> _items) : base() { this.items = _items; }
  83. public override int NumberOfSections (UITableView tableView) { return 1; }
  84. public override int RowsInSection (UITableView tableview,int section) { return this.items.Count; }
  85. public override UITableViewCell GetCell (UITableView tableView,NSIndexPath indexPath)
  86. {
  87. UITableViewCell cell;
  88. cell = tableView.DequeueReusableCell ("item");
  89. if(cell == null)
  90. cell = new UITableViewCell(UITableViewCellStyle.Default,"item");
  91. cell.TextLabel.Text = this.items[indexPath.Row].FirstName + " " + this.items[indexPath.Row].LastName;
  92. return cell;
  93. }
  94. }
  95. }
  96. }

猜你在找的Sqlite相关文章