UWP Sqlite throws database is locked exception - sqlite

When I execute the following code
public async Task<ObservableCollection<CommentModel>> GetTypeWiseComment(int refId, int commentType)
{
try
{
var conn = _dbOperations.GetSyncConnection(DbConnectionType.UserDbConnetion);
var sqlCommand = new SQLiteCommand(conn)
{
CommandText = "bit complex sqlite query"
};
List<CommentModel> commentList = null;
Task commentListTask =
Task.Factory.StartNew(() => commentList = sqlCommand.ExecuteQuery<CommentModel>().ToList());
await commentListTask;
var commentsList = new ObservableCollection<CommentModel>(commentList);
return commentsList;
}
catch (Exception)
{
throw;
}
finally
{
GC.Collect();
}
}
Sometimes I get the following exception
Message: database is locked
InnerException: N/A
StackTrace: at SQLite.SQLite3.Prepare2(IntPtr db, String query)
at SQLite.SQLiteCommand.Prepare()
at SQLite.SQLiteCommand.<ExecuteDeferredQuery>d__12<com.IronOne.BoardPACWinAppBO.Meeting.MeetingModel>.MoveNext()
at System.Collections.Generic.List<System.Diagnostics.Tracing.FieldMetadata>..ctor(Collections.Generic.IEnumerable<System.Diagnostics.Tracing.FieldMetadata> collection)
at BoardPACWinApp!<BaseAddress>+0xaa36ca
at com.IronOne.BoardPACWinAppDAO.Comments.CommentsDAO.<>c__DisplayClass4_0.<GetCommentTypeWiseComment>b__0()
at SharedLibrary!<BaseAddress>+0x38ec7b
at SharedLibrary!<BaseAddress>+0x4978cc
Can anyone point out what's wrong with my code?
There is another sync process going on the background and sometimes it has a bulk of records which may take more than 10 seconds to execute. If this above code happens to execute at the same time as the sync writes to the DB, it might block the reads, right?
If so how do I read from SQLite while another process writes to the DB?
Thank you.

as #Mark Benningfield mentioned enabling WAL mode almost solved my problem. However, there was another issue that creates a lot of SQLite connections on my app so I solved that by creating a Singleton module which handles database connections.
Please comment and ask if you require more information if you encounter a similar issue. Thanks.

Related

TransactionScope: nested transactions with different database connections (SQL Server & Postgresql)

I am writing an SDK method with transaction using NpgsqlConnection for others to use.
When they were calling my method, they used SqlConnection with another transaction to wrap their DB stuff and my SDK's DB stuff.
If I set my SDK method without a transaction, the outer code was fine and my SDK method could be rolled back. (Which was odd too. Still figuring out why.)
If I set my SDK method with a transaction though, the outer code crashed with a TransactionAbortedException:
System.Transactions.TransactionAbortedException : The transaction has aborted.
---- Npgsql.PostgresException : 55000: prepared transactions are disabled
Currently we're using enlist=false at the SDK's connection string to prevent the inner transaction from joining the outer one but I'd like to know the reason behind this behavior.
Here's the code I'm reproducing the problem with:
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted,
},
TransactionScopeAsyncFlowOption.Enabled))
{
await using (var conn = new SqlConnection(#"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0"))
using (var cmd = new SqlCommand("insert into [Test].[dbo].[Test] (Id, \"Name\") values (1, 'A')", conn))
{
await conn.OpenAsync();
var result = await cmd.ExecuteNonQueryAsync();
await SdkMethodToDoStuffWithNpgsql(1);
scope.Complete();
}
}
I had SdkMethodToDoStuffWithNpgsql() to mock a method in a repository with Postgres context injected.
public async Task SdkMethodToDoStuffWithNpgsql(long id)
{
var sqlScript = #"UPDATE test SET is_removal = TRUE WHERE is_removal = FALSE AND id = #id;
INSERT INTO log(id, data) SELECT id, data FROM log WHERE id = #id";
using (var scope = new TransactionScope(
TransactionScopeOption.RequiresNew,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted,
},
TransactionScopeAsyncFlowOption.Enabled))
{
await using (var conn = new NpgsqlConnection(this._context.ConnectionString))
{
await conn.OpenAsync();
using (var cmd = new NpgsqlCommand(sqlScript, conn))
{
cmd.Parameters.Add(new NpgsqlParameter("id", NpgsqlDbType.Bigint) { Value = id });
await cmd.PrepareAsync();
var result = await cmd.ExecuteNonQueryAsync();
if (result != 2)
{
throw new InvalidOperationException("failed");
}
scope.Complete();
}
}
}
}
The above is the expected behavior - enlisting two connections in the same TransactionScope triggers a "distributed transaction"; this is known in PostgreSQL terminology as a "prepared transaction", and you must enable it in the configuration (this is the cause of the error you're seeing above). If the intention is to have two separate transactions (one for SQL Server, one for PostgreSQL) which commit separately, then opting out of enlisting is the right thing to do. You should also be able to use TransactopScopeOption.Suppress.
Note that distributed transactions aren't currently supported in .NET Core, only in .NET Framework (see this issue). So unless you're on .NET Framework, this won't work even if you enable prepared transactions in PostgreSQL.

Entity Framework .Net core FindAsync Throw System.OverflowException: Arithmetic operation resulted in an overflow

I'm trying to create a web API for authentication that return a token.
I'm using .Net core 1.1, EF 1.1.0 and SQL 2014 express on Windows 10. I follow direction from this website to create required classes.
In the middleware class, there's a function called GetIdentity to check the username and password in database. Here is the code
private async Task<ClaimsIdentity> GetIdentity(string username, string password, MyDBContext db) {
try
{
m_user SignedUser = await db.Users.FindAsync(username);
if (SignedUser == null || !SignedUser.password.Equals(password, StringComparison.Ordinal))
throw new ArgumentException("Invalid username or password");
return await Task.FromResult<ClaimsIdentity>(
new ClaimsIdentity(
new GenericIdentity(username, "Token"),
new Claim[] { }
));
}
catch (Exception ex) {Console.WriteLine(ex.Message); return await Task.FromResult<ClaimsIdentity>(null); }
}
When then program hit
m_user SignedUser = await db.Users.FindAsync(username);
It throws System.OverflowException: Arithmetic operation resulted in an overflow.
I didn't get any luck to find the solution or at least the reason why it failed.
Does anyone know why I got that exception?
Thank you for helping me.
P.S: If you need more information, just let me know
I fixed it. I used wrong connection string. I have to put the port number of SQL database in the connection string.
the wrong one:
Server=serverAddress;Database=dbName;User Id=dbUser;Password=dbPassword;
the right one:
Server=serverAddres,portNumber;Database=dbName;User Id=dbUser;Password=dbPassword;
Default MSSQL port number is 1433.
Hope it can help you out if you get same problem with me.
P.S you might get different exception. I got this exception when I tried to run it on VS Code
Like this one:
Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryCompilationContextFactory[1] An exception occurred in the database while iterating the results of a query.

When calling RavenDb store.DatabaseCommands.GlobalAdmin.CreateDatabase() the call hangs

The project that I am currently working on is using RavenDb as an embedded datastore, while attempting to call out to make sure that the database exists in the store, I am finding that it hangs.
var docStore = new EmbeddableDocumentStore()
{
DataDirectory = "Data",
};
docStore.Initialize();
// Check to make sure that the database exists
bool bcDatabaseExists = docStore.DatabaseCommands.GlobalAdmin.GetDatabaseNames(1024).Contains(DatabaseName);
if (!bcDatabaseExists)
{
Dictionary<string, string> settings = new Dictionary<string, string>();
DatabaseDocument databaseDocument = new DatabaseDocument()
{
Id = DatabaseName,
Settings =
{
{ "Raven/DataDir", "~\\Data" }
}
};
try
{
docStore.DatabaseCommands.GlobalAdmin.CreateDatabase(databaseDocument);
}
catch (Exception ex)
{
log.Error(ex);
}
}
However when I hit the CreateDatabase call the process just hangs without any notification. I wanted to check to make sure I wasn't using the call incorrectly, or if there was a better call.
Any thoughts or suggestions that you can offer would be greatly appreciated.
Although the question has nothing to do with NancyFX, probably you need EnsureDatabaseExists method. It will create the database, if it's not there yet.

how does one get csharp-sqlite to throw exceptions for duplicates or foreign key constraint violations

I am currently making use of csharp-sqlite. In the SQLite database I have some uniqueness and foreign key constraints. But when I write a "duplicate" to a table an exception is not raised and the only way I found to check for an exception is to use something like the following:
var error = sqliteCommand.GetLastError();
I was hoping to be able to do the following:
var sqlstring = "some insert sql";
var command = SqliteCommand(sqlstring);
command.Parameters.Add(... some parameter...);
using (var sqlConnection = new SqliteConnection(connectionString))
{
try
{
command.ExecuteNonQuery();
}
catch (Exception ex)
{
do something with the exception
}
finally
{
sqlConnection.Close();
}
}
The "catch" block is never hit, even though the
var error = sqliteCommand.GetLastError();
does return with a description of the error that I was expecting. Does anyone have an idea how to solve this, or what standard practice is using the csharp-sqlite library?

ASP.NET NHibernate transaction duration

Currently in our ASP.NET app we have 1 session per Request, and create one transaction every time we load or update and object. See below:
public static T FindById<T>(object id)
{
ISession session = NHibernateHelper.GetCurrentSession();
ITransaction tx = session.BeginTransaction();
try
{
obj = session.Get<T>(id);
tx.Commit();
}
catch
{
session.Close();
throw;
}
finally
{
tx.Dispose();
}
return obj;
}
public virtual void Save()
{
ISession session = NHibernateHelper.GetCurrentSession();
ITransaction transaction = session.BeginTransaction();
try
{
if (!IsPersisted)
{
session.Save(this);
}
else
{
session.SaveOrUpdateCopy(this);
}
transaction.Commit();
}
catch (HibernateException)
{
if (transaction != null)
{
transaction.Rollback();
}
if (session.IsOpen)
{
session.Close();
}
throw;
}
finally
{
transaction.Dispose();
}
}
Obviously this isn't ideal as it means you create a new connection to the database every time you load or save an object, which incurs performance overhead.
Questions:
If an entity is already loaded in the
1st level cache will the
GetTransaction() call open a database
connection? I suspect it will...
Is there a better way to handle our transaction management so
there are less transactions and therefore
less database connections?
Unfortunately the app code is probably too mature to structure everything like so (with the get and update all in the same transaction):
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction())
{
var post = session.Get<Post>(1);
// do something with post
tx.Commit();
}
Would it be a terrible idea to create one transaction per Request and commit it at the end of the request? I guess the downside is that it ties up one database connection while non-database operations take place.
One transaction Per Request is concidered as best practice with NHibernate. This pattern is implemented in Sharp Architecture.
But in Nhibernate method BeginTransaction() doest open connection to DB. Connection is opened at first real sql request and closed just after query is executed. So Nhibernate holds open connection for some seconds to perform query. You can verify it by SQL Profiler.
Additionally NHiberante always try to use Sql Servers connection pool and that why opening your connection may be not so expensive.
Would it be a terrible idea to create one transaction per Request and commit it at the end of the request
It wouldn't be terrible but I think it's a poor practice. If there is an error and the transaction is rolled back, I would much rather handle it on the page then at the end of the request. I prefer to use one session per request with as many transactions as I need during the request (typically one).
NHibernate is very conscientious about managing its database connections, you don't need to worry about it in most cases.
I don't like your transaction logic, especially since you kill the session if the transaction fails. And I'm not sure why you're calling SaveOrUpdateCopy. NHibernate will detect if the object needs to be persisted so the IsPersisted check is probably not needed. I use this pattern:
using (var txn = session.BeginTransaction())
{
try
{
session.SaveOrUpdate(this);
txn.Commit();
}
catch (Exception ex)
{
txn.Rollback();
// log
// handle, wrap, or throw
}
}

Resources