diff --git a/src/ImageProcessor.Web/Caching/CachedImage.cs b/src/ImageProcessor.Web/Caching/CachedImage.cs
index bc7ef15b7..41241cb1b 100644
--- a/src/ImageProcessor.Web/Caching/CachedImage.cs
+++ b/src/ImageProcessor.Web/Caching/CachedImage.cs
@@ -9,6 +9,9 @@ namespace ImageProcessor.Web.Caching
{
#region Using
using System;
+
+ using SQLite;
+
#endregion
///
@@ -16,28 +19,14 @@ namespace ImageProcessor.Web.Caching
///
internal sealed class CachedImage
{
+ //[PrimaryKey, AutoIncrement]
+ //public int Id { get; set; }
+
///
- /// Initializes a new instance of the class.
+ /// Gets or sets the key identifying the cached image.
///
- ///
- /// The value of the cached image.
- ///
- ///
- /// The max age of the cached image.
- ///
- ///
- /// The last write time of the cached image.
- ///
- ///
- /// The expires time.
- ///
- public CachedImage(string path, int maxAge, DateTime lastWriteTimeUtc, DateTime expiresTimeUtc)
- {
- this.Path = path;
- this.MaxAge = maxAge;
- this.LastWriteTimeUtc = lastWriteTimeUtc;
- this.ExpiresUtc = expiresTimeUtc;
- }
+ [PrimaryKey]
+ internal string Key { get; set; }
///
/// Gets or sets the value of the cached image.
diff --git a/src/ImageProcessor.Web/Caching/DiskCache.cs b/src/ImageProcessor.Web/Caching/DiskCache.cs
index 33d48d19f..6a1f1b841 100644
--- a/src/ImageProcessor.Web/Caching/DiskCache.cs
+++ b/src/ImageProcessor.Web/Caching/DiskCache.cs
@@ -227,7 +227,15 @@ namespace ImageProcessor.Web.Caching
{
string key = Path.GetFileNameWithoutExtension(this.CachedPath);
DateTime expires = DateTime.UtcNow.AddDays(MaxFileCachedDuration).ToUniversalTime();
- CachedImage cachedImage = new CachedImage(this.CachedPath, MaxFileCachedDuration, lastWriteTimeUtc, expires);
+ CachedImage cachedImage = new CachedImage
+ {
+ Key = key,
+ Path = this.CachedPath,
+ MaxAge = MaxFileCachedDuration,
+ LastWriteTimeUtc = lastWriteTimeUtc,
+ ExpiresUtc = expires
+ };
+
await PersistantDictionary.Instance.AddAsync(key, cachedImage);
}
diff --git a/src/ImageProcessor.Web/Caching/PersistantDictionary.cs b/src/ImageProcessor.Web/Caching/PersistantDictionary.cs
index cd868f03c..644d74364 100644
--- a/src/ImageProcessor.Web/Caching/PersistantDictionary.cs
+++ b/src/ImageProcessor.Web/Caching/PersistantDictionary.cs
@@ -130,7 +130,7 @@ namespace ImageProcessor.Web.Caching
return await SQLContext.RemoveImageAsync(key);
}
- return await SQLContext.AddImageAsync(key, cachedImage);
+ return await SQLContext.AddImageAsync(cachedImage);
}
catch
{
diff --git a/src/ImageProcessor.Web/Caching/SQLContext.cs b/src/ImageProcessor.Web/Caching/SQLContext.cs
index 22c2c70d6..1f5be5475 100644
--- a/src/ImageProcessor.Web/Caching/SQLContext.cs
+++ b/src/ImageProcessor.Web/Caching/SQLContext.cs
@@ -8,14 +8,17 @@
namespace ImageProcessor.Web.Caching
{
#region Using
+
using System;
using System.Collections.Generic;
- using System.Data.SQLite;
using System.IO;
using System.Threading.Tasks;
using System.Web.Hosting;
using ImageProcessor.Web.Config;
using ImageProcessor.Web.Helpers;
+
+ using SQLite;
+
#endregion
///
@@ -37,57 +40,44 @@ namespace ImageProcessor.Web.Caching
///
/// The connection string.
///
- private static readonly string ConnectionString = string.Format("Data Source={0};Version=3;", IndexLocation);
+ private static readonly string ConnectionString = IndexLocation;
#endregion
#region Methods
#region Internal
+
///
/// Creates the database if it doesn't already exist.
///
internal static void CreateDatabase()
{
- if (!File.Exists(IndexLocation))
+ try
{
- string absolutePath = HostingEnvironment.MapPath(VirtualCachePath);
-
- if (absolutePath != null)
+ if (!File.Exists(IndexLocation))
{
- DirectoryInfo directoryInfo = new DirectoryInfo(absolutePath);
+ string absolutePath = HostingEnvironment.MapPath(VirtualCachePath);
- if (!directoryInfo.Exists)
+ if (absolutePath != null)
{
- // Create the directory.
- Directory.CreateDirectory(absolutePath);
- }
- }
-
- SQLiteConnection.CreateFile(IndexLocation);
-
- using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
- {
- connection.Open();
+ DirectoryInfo directoryInfo = new DirectoryInfo(absolutePath);
- using (SQLiteTransaction transaction = connection.BeginTransaction())
- {
- using (SQLiteCommand command = new SQLiteCommand(connection))
+ if (!directoryInfo.Exists)
{
- command.CommandText = @"CREATE TABLE names
- (Key TEXT,
- Path TEXT,
- MaxAge INTEGER,
- LastWriteTimeUtc TEXT,
- ExpiresUtc TEXT,
- PRIMARY KEY (Key),
- UNIQUE (Path));";
-
- command.ExecuteNonQuery();
+ // Create the directory.
+ Directory.CreateDirectory(absolutePath);
}
+ }
- transaction.Commit();
+ using (SQLiteConnection connection = new SQLiteConnection(IndexLocation))
+ {
+ connection.CreateTable();
}
}
}
+ catch (Exception ex)
+ {
+ throw ex;
+ }
}
///
@@ -104,25 +94,11 @@ namespace ImageProcessor.Web.Caching
{
using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
{
- connection.Open();
+ List images = connection.Query("SELECT * FROM CachedImage");
- using (SQLiteCommand command = new SQLiteCommand(connection))
+ foreach (CachedImage cachedImage in images)
{
- command.CommandText = "SELECT * FROM names;";
-
- SQLiteDataReader reader = command.ExecuteReader();
-
- while (reader.Read())
- {
- string key = reader["Key"].ToString();
- CachedImage image = new CachedImage(
- reader["Path"].ToString(),
- int.Parse(reader["MaxAge"].ToString()),
- DateTime.Parse(reader["LastWriteTimeUtc"].ToString()).ToUniversalTime(),
- DateTime.Parse(reader["ExpiresUtc"].ToString()).ToUniversalTime());
-
- dictionary.Add(key, image);
- }
+ dictionary.Add(cachedImage.Key, cachedImage);
}
}
@@ -137,19 +113,16 @@ namespace ImageProcessor.Web.Caching
///
/// Adds a cached image to the database.
///
- ///
- /// The key for the cached image.
- ///
///
/// The cached image to add.
///
///
/// The true if the addition of the cached image is added; otherwise, false.
///
- internal static async Task AddImageAsync(string key, CachedImage image)
+ internal static async Task AddImageAsync(CachedImage image)
{
// Create Action delegate for AddImage.
- return await TaskHelpers.Run(() => AddImage(key, image));
+ return await TaskHelpers.Run(() => AddImage(image));
}
///
@@ -169,48 +142,28 @@ namespace ImageProcessor.Web.Caching
#endregion
#region Private
+
///
/// Adds a cached image to the database.
///
- ///
- /// The key for the cached image.
- ///
///
/// The cached image to add.
///
///
/// The true if the addition of the cached image is added; otherwise, false.
///
- private static bool AddImage(string key, CachedImage image)
+ private static bool AddImage(CachedImage image)
{
try
{
- using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
- {
- connection.Open();
+ SQLiteConnection connection = new SQLiteConnection(ConnectionString);
- using (SQLiteTransaction transaction = connection.BeginTransaction())
+ connection.RunInTransaction(() =>
{
- using (SQLiteCommand command = new SQLiteCommand(connection))
- {
- command.CommandText = "INSERT INTO names VALUES(?, ?, ?, ?, ?)";
-
- SQLiteParameter[] parameters = new[]
- {
- new SQLiteParameter("Key", key),
- new SQLiteParameter("Path", image.Path),
- new SQLiteParameter("MaxAge", image.MaxAge),
- new SQLiteParameter("LastWriteTimeUtc", image.LastWriteTimeUtc),
- new SQLiteParameter("ExpiresUtc", image.ExpiresUtc)
- };
-
- command.Parameters.AddRange(parameters);
- command.ExecuteNonQuery();
- }
-
- transaction.Commit();
- }
- }
+ // Database calls inside the transaction
+ connection.Insert(image);
+ connection.Dispose();
+ });
return true;
}
@@ -233,22 +186,14 @@ namespace ImageProcessor.Web.Caching
{
try
{
- using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
- {
- connection.Open();
+ SQLiteConnection connection = new SQLiteConnection(ConnectionString);
- using (SQLiteTransaction transaction = connection.BeginTransaction())
- {
- using (SQLiteCommand command = new SQLiteCommand(connection))
- {
- command.CommandText = "DELETE FROM names WHERE key = @searchParam;";
- command.Parameters.Add(new SQLiteParameter("searchParam", key));
- command.ExecuteNonQuery();
- }
-
- transaction.Commit();
- }
- }
+ connection.RunInTransaction(() =>
+ {
+ // Database calls inside the transaction
+ connection.Delete(key);
+ connection.Dispose();
+ });
return true;
}
diff --git a/src/ImageProcessor.Web/ImageProcessor.Web.csproj b/src/ImageProcessor.Web/ImageProcessor.Web.csproj
index 21ce0661c..60e5b6ed6 100644
--- a/src/ImageProcessor.Web/ImageProcessor.Web.csproj
+++ b/src/ImageProcessor.Web/ImageProcessor.Web.csproj
@@ -18,7 +18,7 @@
full
false
bin\Debug\
- DEBUG;TRACE
+ TRACE;DEBUG;USE_CSHARP_SQLITE
prompt
4
@@ -66,6 +66,12 @@
MinimumRecommendedRules.ruleset
+
+ ..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.dll
+
+
+ ..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.SQLiteClient.dll
+
..\packages\Microsoft.Bcl.Async.1.0.14-rc\lib\net40\Microsoft.Threading.Tasks.dll
@@ -78,10 +84,6 @@
-
- False
- ..\packages\SQLitex64.1.0.66\lib\32\System.Data.SQLite.DLL
-
@@ -108,6 +110,8 @@
+
+
diff --git a/src/ImageProcessor.Web/SQLite.cs.REMOVED.git-id b/src/ImageProcessor.Web/SQLite.cs.REMOVED.git-id
new file mode 100644
index 000000000..ee7e14fe9
--- /dev/null
+++ b/src/ImageProcessor.Web/SQLite.cs.REMOVED.git-id
@@ -0,0 +1 @@
+ce0491dcbe39702bf25fb616f76e1b149f670688
\ No newline at end of file
diff --git a/src/ImageProcessor.Web/SQLiteAsync.cs b/src/ImageProcessor.Web/SQLiteAsync.cs
new file mode 100644
index 000000000..b4cf34e07
--- /dev/null
+++ b/src/ImageProcessor.Web/SQLiteAsync.cs
@@ -0,0 +1,486 @@
+//
+// Copyright (c) 2012 Krueger Systems, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SQLite
+{
+ public partial class SQLiteAsyncConnection
+ {
+ SQLiteConnectionString _connectionString;
+
+ public SQLiteAsyncConnection (string databasePath, bool storeDateTimeAsTicks = false)
+ {
+ _connectionString = new SQLiteConnectionString (databasePath, storeDateTimeAsTicks);
+ }
+
+ SQLiteConnectionWithLock GetConnection ()
+ {
+ return SQLiteConnectionPool.Shared.GetConnection (_connectionString);
+ }
+
+ public Task CreateTableAsync ()
+ where T : new ()
+ {
+ return CreateTablesAsync (typeof (T));
+ }
+
+ public Task CreateTablesAsync ()
+ where T : new ()
+ where T2 : new ()
+ {
+ return CreateTablesAsync (typeof (T), typeof (T2));
+ }
+
+ public Task CreateTablesAsync ()
+ where T : new ()
+ where T2 : new ()
+ where T3 : new ()
+ {
+ return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3));
+ }
+
+ public Task CreateTablesAsync ()
+ where T : new ()
+ where T2 : new ()
+ where T3 : new ()
+ where T4 : new ()
+ {
+ return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3), typeof (T4));
+ }
+
+ public Task CreateTablesAsync ()
+ where T : new ()
+ where T2 : new ()
+ where T3 : new ()
+ where T4 : new ()
+ where T5 : new ()
+ {
+ return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3), typeof (T4), typeof (T5));
+ }
+
+ public Task CreateTablesAsync (params Type[] types)
+ {
+ return Task.Factory.StartNew (() => {
+ CreateTablesResult result = new CreateTablesResult ();
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ foreach (Type type in types) {
+ int aResult = conn.CreateTable (type);
+ result.Results[type] = aResult;
+ }
+ }
+ return result;
+ });
+ }
+
+ public Task DropTableAsync ()
+ where T : new ()
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.DropTable ();
+ }
+ });
+ }
+
+ public Task InsertAsync (object item)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Insert (item);
+ }
+ });
+ }
+
+ public Task UpdateAsync (object item)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Update (item);
+ }
+ });
+ }
+
+ public Task DeleteAsync (object item)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Delete (item);
+ }
+ });
+ }
+
+ public Task GetAsync(object pk)
+ where T : new()
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ var conn = GetConnection();
+ using (conn.Lock())
+ {
+ return conn.Get(pk);
+ }
+ });
+ }
+
+ public Task FindAsync (object pk)
+ where T : new ()
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Find (pk);
+ }
+ });
+ }
+
+ public Task GetAsync (Expression> predicate)
+ where T : new()
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ var conn = GetConnection();
+ using (conn.Lock())
+ {
+ return conn.Get (predicate);
+ }
+ });
+ }
+
+ public Task FindAsync (Expression> predicate)
+ where T : new ()
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Find (predicate);
+ }
+ });
+ }
+
+ public Task ExecuteAsync (string query, params object[] args)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Execute (query, args);
+ }
+ });
+ }
+
+ public Task InsertAllAsync (IEnumerable items)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.InsertAll (items);
+ }
+ });
+ }
+
+ [Obsolete("Will cause a deadlock if any call in action ends up in a different thread. Use RunInTransactionAsync(Action) instead.")]
+ public Task RunInTransactionAsync (Action action)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = this.GetConnection ();
+ using (conn.Lock ()) {
+ conn.BeginTransaction ();
+ try {
+ action (this);
+ conn.Commit ();
+ }
+ catch (Exception) {
+ conn.Rollback ();
+ throw;
+ }
+ }
+ });
+ }
+
+ public Task RunInTransactionAsync(Action action)
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ var conn = this.GetConnection();
+ using (conn.Lock())
+ {
+ conn.BeginTransaction();
+ try
+ {
+ action(conn);
+ conn.Commit();
+ }
+ catch (Exception)
+ {
+ conn.Rollback();
+ throw;
+ }
+ }
+ });
+ }
+
+ public AsyncTableQuery Table ()
+ where T : new ()
+ {
+ //
+ // This isn't async as the underlying connection doesn't go out to the database
+ // until the query is performed. The Async methods are on the query iteself.
+ //
+ var conn = GetConnection ();
+ return new AsyncTableQuery (conn.Table ());
+ }
+
+ public Task ExecuteScalarAsync (string sql, params object[] args)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ var command = conn.CreateCommand (sql, args);
+ return command.ExecuteScalar ();
+ }
+ });
+ }
+
+ public Task> QueryAsync (string sql, params object[] args)
+ where T : new ()
+ {
+ return Task>.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Query (sql, args);
+ }
+ });
+ }
+ }
+
+ //
+ // TODO: Bind to AsyncConnection.GetConnection instead so that delayed
+ // execution can still work after a Pool.Reset.
+ //
+ public class AsyncTableQuery
+ where T : new ()
+ {
+ TableQuery _innerQuery;
+
+ public AsyncTableQuery (TableQuery innerQuery)
+ {
+ _innerQuery = innerQuery;
+ }
+
+ public AsyncTableQuery Where (Expression> predExpr)
+ {
+ return new AsyncTableQuery (_innerQuery.Where (predExpr));
+ }
+
+ public AsyncTableQuery Skip (int n)
+ {
+ return new AsyncTableQuery (_innerQuery.Skip (n));
+ }
+
+ public AsyncTableQuery Take (int n)
+ {
+ return new AsyncTableQuery (_innerQuery.Take (n));
+ }
+
+ public AsyncTableQuery OrderBy (Expression> orderExpr)
+ {
+ return new AsyncTableQuery (_innerQuery.OrderBy (orderExpr));
+ }
+
+ public AsyncTableQuery OrderByDescending (Expression> orderExpr)
+ {
+ return new AsyncTableQuery (_innerQuery.OrderByDescending (orderExpr));
+ }
+
+ public Task> ToListAsync ()
+ {
+ return Task.Factory.StartNew (() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.ToList ();
+ }
+ });
+ }
+
+ public Task CountAsync ()
+ {
+ return Task.Factory.StartNew (() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.Count ();
+ }
+ });
+ }
+
+ public Task ElementAtAsync (int index)
+ {
+ return Task.Factory.StartNew (() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.ElementAt (index);
+ }
+ });
+ }
+
+ public Task FirstAsync ()
+ {
+ return Task.Factory.StartNew(() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.First ();
+ }
+ });
+ }
+
+ public Task FirstOrDefaultAsync ()
+ {
+ return Task.Factory.StartNew(() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.FirstOrDefault ();
+ }
+ });
+ }
+ }
+
+ public class CreateTablesResult
+ {
+ public Dictionary Results { get; private set; }
+
+ internal CreateTablesResult ()
+ {
+ this.Results = new Dictionary ();
+ }
+ }
+
+ class SQLiteConnectionPool
+ {
+ class Entry
+ {
+ public SQLiteConnectionString ConnectionString { get; private set; }
+ public SQLiteConnectionWithLock Connection { get; private set; }
+
+ public Entry (SQLiteConnectionString connectionString)
+ {
+ ConnectionString = connectionString;
+ Connection = new SQLiteConnectionWithLock (connectionString);
+ }
+
+ public void OnApplicationSuspended ()
+ {
+ Connection.Dispose ();
+ Connection = null;
+ }
+ }
+
+ readonly Dictionary _entries = new Dictionary ();
+ readonly object _entriesLock = new object ();
+
+ static readonly SQLiteConnectionPool _shared = new SQLiteConnectionPool ();
+
+ ///
+ /// Gets the singleton instance of the connection tool.
+ ///
+ public static SQLiteConnectionPool Shared
+ {
+ get
+ {
+ return _shared;
+ }
+ }
+
+ public SQLiteConnectionWithLock GetConnection (SQLiteConnectionString connectionString)
+ {
+ lock (_entriesLock) {
+ Entry entry;
+ string key = connectionString.ConnectionString;
+
+ if (!_entries.TryGetValue (key, out entry)) {
+ entry = new Entry (connectionString);
+ _entries[key] = entry;
+ }
+
+ return entry.Connection;
+ }
+ }
+
+ ///
+ /// Closes all connections managed by this pool.
+ ///
+ public void Reset ()
+ {
+ lock (_entriesLock) {
+ foreach (var entry in _entries.Values) {
+ entry.OnApplicationSuspended ();
+ }
+ _entries.Clear ();
+ }
+ }
+
+ ///
+ /// Call this method when the application is suspended.
+ ///
+ /// Behaviour here is to close any open connections.
+ public void ApplicationSuspended ()
+ {
+ Reset ();
+ }
+ }
+
+ class SQLiteConnectionWithLock : SQLiteConnection
+ {
+ readonly object _lockPoint = new object ();
+
+ public SQLiteConnectionWithLock (SQLiteConnectionString connectionString)
+ : base (connectionString.DatabasePath, connectionString.StoreDateTimeAsTicks)
+ {
+ }
+
+ public IDisposable Lock ()
+ {
+ return new LockWrapper (_lockPoint);
+ }
+
+ private class LockWrapper : IDisposable
+ {
+ object _lockPoint;
+
+ public LockWrapper (object lockPoint)
+ {
+ _lockPoint = lockPoint;
+ Monitor.Enter (_lockPoint);
+ }
+
+ public void Dispose ()
+ {
+ Monitor.Exit (_lockPoint);
+ }
+ }
+ }
+}
+
diff --git a/src/ImageProcessor.Web/packages.config b/src/ImageProcessor.Web/packages.config
index 58ea5f418..c3bf2d679 100644
--- a/src/ImageProcessor.Web/packages.config
+++ b/src/ImageProcessor.Web/packages.config
@@ -1,7 +1,8 @@
+
-
+
\ No newline at end of file
diff --git a/src/Test/Test/Web.config b/src/Test/Test/Web.config
index f6e8b95f0..09f93bfb9 100644
--- a/src/Test/Test/Web.config
+++ b/src/Test/Test/Web.config
@@ -4,84 +4,84 @@
http://go.microsoft.com/fwlink/?LinkId=152368
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/packages/Csharp-Sqlite.3.7.7.1/Csharp-Sqlite.3.7.7.1.nupkg.REMOVED.git-id b/src/packages/Csharp-Sqlite.3.7.7.1/Csharp-Sqlite.3.7.7.1.nupkg.REMOVED.git-id
new file mode 100644
index 000000000..873e6cddd
--- /dev/null
+++ b/src/packages/Csharp-Sqlite.3.7.7.1/Csharp-Sqlite.3.7.7.1.nupkg.REMOVED.git-id
@@ -0,0 +1 @@
+81fffff68e71d82a09d8c6a345ce69410f351786
\ No newline at end of file
diff --git a/src/packages/Csharp-Sqlite.3.7.7.1/Csharp-Sqlite.3.7.7.1.nuspec b/src/packages/Csharp-Sqlite.3.7.7.1/Csharp-Sqlite.3.7.7.1.nuspec
new file mode 100644
index 000000000..574462183
--- /dev/null
+++ b/src/packages/Csharp-Sqlite.3.7.7.1/Csharp-Sqlite.3.7.7.1.nuspec
@@ -0,0 +1,21 @@
+
+
+
+ Csharp-Sqlite
+ 3.7.7.1
+ C#-SqLite Unofficial Package
+ noah.hart
+ noah.hart
+ http://code.google.com/p/csharp-sqlite/
+ false
+ C#-SQLite is an independent reimplementation of the SQLite software library version 3.7.7.1.
+
+
+
+ Sqlite
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/packages/Csharp-Sqlite.3.7.7.1/lib/net20/Community.CsharpSqlite.SQLiteClient.dll b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net20/Community.CsharpSqlite.SQLiteClient.dll
new file mode 100644
index 000000000..471796b1b
Binary files /dev/null and b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net20/Community.CsharpSqlite.SQLiteClient.dll differ
diff --git a/src/packages/Csharp-Sqlite.3.7.7.1/lib/net20/Community.CsharpSqlite.dll.REMOVED.git-id b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net20/Community.CsharpSqlite.dll.REMOVED.git-id
new file mode 100644
index 000000000..cce826f42
--- /dev/null
+++ b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net20/Community.CsharpSqlite.dll.REMOVED.git-id
@@ -0,0 +1 @@
+703605507a2c2a90fa7b826aaf2cf7c78a7243b7
\ No newline at end of file
diff --git a/src/packages/Csharp-Sqlite.3.7.7.1/lib/net35/Community.CsharpSqlite.SQLiteClient.dll b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net35/Community.CsharpSqlite.SQLiteClient.dll
new file mode 100644
index 000000000..cb54313fe
Binary files /dev/null and b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net35/Community.CsharpSqlite.SQLiteClient.dll differ
diff --git a/src/packages/Csharp-Sqlite.3.7.7.1/lib/net35/Community.CsharpSqlite.dll.REMOVED.git-id b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net35/Community.CsharpSqlite.dll.REMOVED.git-id
new file mode 100644
index 000000000..75db259e4
--- /dev/null
+++ b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net35/Community.CsharpSqlite.dll.REMOVED.git-id
@@ -0,0 +1 @@
+2e6a85ddf4ce868ed48de14c2be21ee94f689b78
\ No newline at end of file
diff --git a/src/packages/Csharp-Sqlite.3.7.7.1/lib/net40/Community.CsharpSqlite.SQLiteClient.dll b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net40/Community.CsharpSqlite.SQLiteClient.dll
new file mode 100644
index 000000000..aba80685c
Binary files /dev/null and b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net40/Community.CsharpSqlite.SQLiteClient.dll differ
diff --git a/src/packages/Csharp-Sqlite.3.7.7.1/lib/net40/Community.CsharpSqlite.dll.REMOVED.git-id b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net40/Community.CsharpSqlite.dll.REMOVED.git-id
new file mode 100644
index 000000000..ecea89996
--- /dev/null
+++ b/src/packages/Csharp-Sqlite.3.7.7.1/lib/net40/Community.CsharpSqlite.dll.REMOVED.git-id
@@ -0,0 +1 @@
+ab181a987d0059a31c26ee3891a01c40d43019a0
\ No newline at end of file
diff --git a/src/packages/SQLitex64.1.0.66/SQLitex64.1.0.66.nupkg.REMOVED.git-id b/src/packages/SQLitex64.1.0.66/SQLitex64.1.0.66.nupkg.REMOVED.git-id
deleted file mode 100644
index 6e8c802e1..000000000
--- a/src/packages/SQLitex64.1.0.66/SQLitex64.1.0.66.nupkg.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-aff828512d1afca48fa5d6824429359562199078
\ No newline at end of file
diff --git a/src/packages/SQLitex64.1.0.66/SQLitex64.1.0.66.nuspec b/src/packages/SQLitex64.1.0.66/SQLitex64.1.0.66.nuspec
deleted file mode 100644
index 2275c52d5..000000000
--- a/src/packages/SQLitex64.1.0.66/SQLitex64.1.0.66.nuspec
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
- SQLitex64
- 1.0.66
- SQLitex64
- Amir Barylko
- Amir Barylko
- http://www.sqlite.org/
- http://www.sqlite.org/images/sqlite370_banner.gif
- false
- Provides both (32 and 64 bit) assemblies needed to use SQLite.
-The current package only provides 32 bit.
- SQLite 64 bit and 32 bit assemblies
-
-
-
- SQLite
-
-
-
-
-
\ No newline at end of file
diff --git a/src/packages/SQLitex64.1.0.66/lib/32/System.Data.SQLite.DLL.REMOVED.git-id b/src/packages/SQLitex64.1.0.66/lib/32/System.Data.SQLite.DLL.REMOVED.git-id
deleted file mode 100644
index f6116a77c..000000000
--- a/src/packages/SQLitex64.1.0.66/lib/32/System.Data.SQLite.DLL.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-aa398bbec1a567de55f984959d200900b794372a
\ No newline at end of file
diff --git a/src/packages/SQLitex64.1.0.66/lib/64/System.Data.SQLite.DLL.REMOVED.git-id b/src/packages/SQLitex64.1.0.66/lib/64/System.Data.SQLite.DLL.REMOVED.git-id
deleted file mode 100644
index acf4e1240..000000000
--- a/src/packages/SQLitex64.1.0.66/lib/64/System.Data.SQLite.DLL.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-6f07d5e7ab41a0f791f07d5407f10edb4b716a02
\ No newline at end of file
diff --git a/src/packages/SQLitex64.1.0.66/lib/System.Data.SQLite.DLL.REMOVED.git-id b/src/packages/SQLitex64.1.0.66/lib/System.Data.SQLite.DLL.REMOVED.git-id
deleted file mode 100644
index f6116a77c..000000000
--- a/src/packages/SQLitex64.1.0.66/lib/System.Data.SQLite.DLL.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-aa398bbec1a567de55f984959d200900b794372a
\ No newline at end of file
diff --git a/src/packages/sqlite-net.1.0.7/content/SQLite.cs.REMOVED.git-id b/src/packages/sqlite-net.1.0.7/content/SQLite.cs.REMOVED.git-id
new file mode 100644
index 000000000..2dfc5c248
--- /dev/null
+++ b/src/packages/sqlite-net.1.0.7/content/SQLite.cs.REMOVED.git-id
@@ -0,0 +1 @@
+d2856e3733eb6c7d85057c37ae415e54c8bf2386
\ No newline at end of file
diff --git a/src/packages/sqlite-net.1.0.7/content/SQLiteAsync.cs b/src/packages/sqlite-net.1.0.7/content/SQLiteAsync.cs
new file mode 100644
index 000000000..b4cf34e07
--- /dev/null
+++ b/src/packages/sqlite-net.1.0.7/content/SQLiteAsync.cs
@@ -0,0 +1,486 @@
+//
+// Copyright (c) 2012 Krueger Systems, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SQLite
+{
+ public partial class SQLiteAsyncConnection
+ {
+ SQLiteConnectionString _connectionString;
+
+ public SQLiteAsyncConnection (string databasePath, bool storeDateTimeAsTicks = false)
+ {
+ _connectionString = new SQLiteConnectionString (databasePath, storeDateTimeAsTicks);
+ }
+
+ SQLiteConnectionWithLock GetConnection ()
+ {
+ return SQLiteConnectionPool.Shared.GetConnection (_connectionString);
+ }
+
+ public Task CreateTableAsync ()
+ where T : new ()
+ {
+ return CreateTablesAsync (typeof (T));
+ }
+
+ public Task CreateTablesAsync ()
+ where T : new ()
+ where T2 : new ()
+ {
+ return CreateTablesAsync (typeof (T), typeof (T2));
+ }
+
+ public Task CreateTablesAsync ()
+ where T : new ()
+ where T2 : new ()
+ where T3 : new ()
+ {
+ return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3));
+ }
+
+ public Task CreateTablesAsync ()
+ where T : new ()
+ where T2 : new ()
+ where T3 : new ()
+ where T4 : new ()
+ {
+ return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3), typeof (T4));
+ }
+
+ public Task CreateTablesAsync ()
+ where T : new ()
+ where T2 : new ()
+ where T3 : new ()
+ where T4 : new ()
+ where T5 : new ()
+ {
+ return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3), typeof (T4), typeof (T5));
+ }
+
+ public Task CreateTablesAsync (params Type[] types)
+ {
+ return Task.Factory.StartNew (() => {
+ CreateTablesResult result = new CreateTablesResult ();
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ foreach (Type type in types) {
+ int aResult = conn.CreateTable (type);
+ result.Results[type] = aResult;
+ }
+ }
+ return result;
+ });
+ }
+
+ public Task DropTableAsync ()
+ where T : new ()
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.DropTable ();
+ }
+ });
+ }
+
+ public Task InsertAsync (object item)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Insert (item);
+ }
+ });
+ }
+
+ public Task UpdateAsync (object item)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Update (item);
+ }
+ });
+ }
+
+ public Task DeleteAsync (object item)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Delete (item);
+ }
+ });
+ }
+
+ public Task GetAsync(object pk)
+ where T : new()
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ var conn = GetConnection();
+ using (conn.Lock())
+ {
+ return conn.Get(pk);
+ }
+ });
+ }
+
+ public Task FindAsync (object pk)
+ where T : new ()
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Find (pk);
+ }
+ });
+ }
+
+ public Task GetAsync (Expression> predicate)
+ where T : new()
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ var conn = GetConnection();
+ using (conn.Lock())
+ {
+ return conn.Get (predicate);
+ }
+ });
+ }
+
+ public Task FindAsync (Expression> predicate)
+ where T : new ()
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Find (predicate);
+ }
+ });
+ }
+
+ public Task ExecuteAsync (string query, params object[] args)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Execute (query, args);
+ }
+ });
+ }
+
+ public Task InsertAllAsync (IEnumerable items)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.InsertAll (items);
+ }
+ });
+ }
+
+ [Obsolete("Will cause a deadlock if any call in action ends up in a different thread. Use RunInTransactionAsync(Action) instead.")]
+ public Task RunInTransactionAsync (Action action)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = this.GetConnection ();
+ using (conn.Lock ()) {
+ conn.BeginTransaction ();
+ try {
+ action (this);
+ conn.Commit ();
+ }
+ catch (Exception) {
+ conn.Rollback ();
+ throw;
+ }
+ }
+ });
+ }
+
+ public Task RunInTransactionAsync(Action action)
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ var conn = this.GetConnection();
+ using (conn.Lock())
+ {
+ conn.BeginTransaction();
+ try
+ {
+ action(conn);
+ conn.Commit();
+ }
+ catch (Exception)
+ {
+ conn.Rollback();
+ throw;
+ }
+ }
+ });
+ }
+
+ public AsyncTableQuery Table ()
+ where T : new ()
+ {
+ //
+ // This isn't async as the underlying connection doesn't go out to the database
+ // until the query is performed. The Async methods are on the query iteself.
+ //
+ var conn = GetConnection ();
+ return new AsyncTableQuery (conn.Table ());
+ }
+
+ public Task ExecuteScalarAsync (string sql, params object[] args)
+ {
+ return Task.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ var command = conn.CreateCommand (sql, args);
+ return command.ExecuteScalar ();
+ }
+ });
+ }
+
+ public Task> QueryAsync (string sql, params object[] args)
+ where T : new ()
+ {
+ return Task>.Factory.StartNew (() => {
+ var conn = GetConnection ();
+ using (conn.Lock ()) {
+ return conn.Query (sql, args);
+ }
+ });
+ }
+ }
+
+ //
+ // TODO: Bind to AsyncConnection.GetConnection instead so that delayed
+ // execution can still work after a Pool.Reset.
+ //
+ public class AsyncTableQuery
+ where T : new ()
+ {
+ TableQuery _innerQuery;
+
+ public AsyncTableQuery (TableQuery innerQuery)
+ {
+ _innerQuery = innerQuery;
+ }
+
+ public AsyncTableQuery Where (Expression> predExpr)
+ {
+ return new AsyncTableQuery (_innerQuery.Where (predExpr));
+ }
+
+ public AsyncTableQuery Skip (int n)
+ {
+ return new AsyncTableQuery (_innerQuery.Skip (n));
+ }
+
+ public AsyncTableQuery Take (int n)
+ {
+ return new AsyncTableQuery (_innerQuery.Take (n));
+ }
+
+ public AsyncTableQuery OrderBy (Expression> orderExpr)
+ {
+ return new AsyncTableQuery (_innerQuery.OrderBy (orderExpr));
+ }
+
+ public AsyncTableQuery OrderByDescending (Expression> orderExpr)
+ {
+ return new AsyncTableQuery (_innerQuery.OrderByDescending (orderExpr));
+ }
+
+ public Task> ToListAsync ()
+ {
+ return Task.Factory.StartNew (() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.ToList ();
+ }
+ });
+ }
+
+ public Task CountAsync ()
+ {
+ return Task.Factory.StartNew (() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.Count ();
+ }
+ });
+ }
+
+ public Task ElementAtAsync (int index)
+ {
+ return Task.Factory.StartNew (() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.ElementAt (index);
+ }
+ });
+ }
+
+ public Task FirstAsync ()
+ {
+ return Task.Factory.StartNew(() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.First ();
+ }
+ });
+ }
+
+ public Task FirstOrDefaultAsync ()
+ {
+ return Task.Factory.StartNew(() => {
+ using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
+ return _innerQuery.FirstOrDefault ();
+ }
+ });
+ }
+ }
+
+ public class CreateTablesResult
+ {
+ public Dictionary Results { get; private set; }
+
+ internal CreateTablesResult ()
+ {
+ this.Results = new Dictionary ();
+ }
+ }
+
+ class SQLiteConnectionPool
+ {
+ class Entry
+ {
+ public SQLiteConnectionString ConnectionString { get; private set; }
+ public SQLiteConnectionWithLock Connection { get; private set; }
+
+ public Entry (SQLiteConnectionString connectionString)
+ {
+ ConnectionString = connectionString;
+ Connection = new SQLiteConnectionWithLock (connectionString);
+ }
+
+ public void OnApplicationSuspended ()
+ {
+ Connection.Dispose ();
+ Connection = null;
+ }
+ }
+
+ readonly Dictionary _entries = new Dictionary ();
+ readonly object _entriesLock = new object ();
+
+ static readonly SQLiteConnectionPool _shared = new SQLiteConnectionPool ();
+
+ ///
+ /// Gets the singleton instance of the connection tool.
+ ///
+ public static SQLiteConnectionPool Shared
+ {
+ get
+ {
+ return _shared;
+ }
+ }
+
+ public SQLiteConnectionWithLock GetConnection (SQLiteConnectionString connectionString)
+ {
+ lock (_entriesLock) {
+ Entry entry;
+ string key = connectionString.ConnectionString;
+
+ if (!_entries.TryGetValue (key, out entry)) {
+ entry = new Entry (connectionString);
+ _entries[key] = entry;
+ }
+
+ return entry.Connection;
+ }
+ }
+
+ ///
+ /// Closes all connections managed by this pool.
+ ///
+ public void Reset ()
+ {
+ lock (_entriesLock) {
+ foreach (var entry in _entries.Values) {
+ entry.OnApplicationSuspended ();
+ }
+ _entries.Clear ();
+ }
+ }
+
+ ///
+ /// Call this method when the application is suspended.
+ ///
+ /// Behaviour here is to close any open connections.
+ public void ApplicationSuspended ()
+ {
+ Reset ();
+ }
+ }
+
+ class SQLiteConnectionWithLock : SQLiteConnection
+ {
+ readonly object _lockPoint = new object ();
+
+ public SQLiteConnectionWithLock (SQLiteConnectionString connectionString)
+ : base (connectionString.DatabasePath, connectionString.StoreDateTimeAsTicks)
+ {
+ }
+
+ public IDisposable Lock ()
+ {
+ return new LockWrapper (_lockPoint);
+ }
+
+ private class LockWrapper : IDisposable
+ {
+ object _lockPoint;
+
+ public LockWrapper (object lockPoint)
+ {
+ _lockPoint = lockPoint;
+ Monitor.Enter (_lockPoint);
+ }
+
+ public void Dispose ()
+ {
+ Monitor.Exit (_lockPoint);
+ }
+ }
+ }
+}
+
diff --git a/src/packages/sqlite-net.1.0.7/sqlite-net.1.0.7.nupkg b/src/packages/sqlite-net.1.0.7/sqlite-net.1.0.7.nupkg
new file mode 100644
index 000000000..64dd2824f
Binary files /dev/null and b/src/packages/sqlite-net.1.0.7/sqlite-net.1.0.7.nupkg differ
diff --git a/src/packages/sqlite-net.1.0.7/sqlite-net.1.0.7.nuspec b/src/packages/sqlite-net.1.0.7/sqlite-net.1.0.7.nuspec
new file mode 100644
index 000000000..ad44185a8
--- /dev/null
+++ b/src/packages/sqlite-net.1.0.7/sqlite-net.1.0.7.nuspec
@@ -0,0 +1,20 @@
+
+
+
+ sqlite-net
+ 1.0.7
+ sqlite-net
+ Frank Krueger
+ Frank Krueger
+ https://github.com/praeclarum/sqlite-net/blob/master/license.md
+ https://github.com/praeclarum/sqlite-net
+ false
+ sqlite-net is an open source, minimal library to allow .NET and Mono applications to store data in SQLite databases. It is written in C# 3.0 and is meant to be simply compiled in with your projects. It was first designed to work with MonoTouch on the iPhone, but should work in any other CLI environment.
+ A .NET client library to access SQLite embedded database files in a LINQ manner.
+ v1.0.7: Update with commits through 06-FEB-2013.
+
+
+ sqlite sql monotouch database metro winrt
+
+
+
\ No newline at end of file