I'm at a complete loss here. I have two tests: Update_Task and Get_All_Tasks. When run individually, they pass. If I run them together in Visual Studio 2015 (not in parallel -- just selecting them both and clicking run) Update_Task passes and Get_All_Tasks does not. For the latter, I get an error message saying that the database is locked. This implies that Update_Task locks the database and fails to release the lock, but I can't figure out where that would do it.
Any thoughts? Code follows.
EDIT: I found the answer.
It turns out that when you do a var reader = cmd.ExecuteReader()
, that reader needs to be put in a using
block itself. Otherwise, the reader may not close and that caused the lock. Doing this fixed the problem:
using (var reader = cmd.ExecuteReader())
{
// The query will return only one item, so read it into a new task.
reader.Read();
return this.GetTaskFromReader(reader);
}
Test Methods
[TestMethod]
public void Update_Task()
{
var dbMan = new DatabaseManager();
// Add a new task
var t = new Task()
{
IsEnabled = true,
Description = "Test",
DueDate = DateTime.Now,
Priority = Priority.High
};
dbMan.InsertTask(t);
// Alter the task and update it
t.IsEnabled = false;
t.Description = "Updated test";
t.DueDate = DateTime.Now.AddDays(1);
t.Priority = Priority.Medium;
var updatedTask = this.UpdateTaskAndRetrieve(dbMan, t);
Assert.AreEqual(t, updatedTask, "Task did not update correctly.");
}
[TestMethod]
public void Get_All_Tasks()
{
var dbMan = new DatabaseManager();
// Get the number of tasks currently in the database
var originalCount = dbMan.GetAllTasks().Count;
// Add 5 tasks with different values
for (int i = 0; i < 5; i++)
{
var t = new Task()
{
IsEnabled = i % 2 == 0,
Description = $"Task {i + 1}",
DueDate = DateTime.Now.AddDays(i),
Priority = (Priority)(i % 4)
};
dbMan.InsertTask(t); // <-- Fails when i == 0
}
// Get all the tasks in the database.
var result = dbMan.GetAllTasks();
Assert.AreEqual(originalCount + 5, result.Count, "Wrong number of tasks came back from the database.");
}
private Task UpdateTaskAndRetrieve(DatabaseManager dbMan, Task t)
{
dbMan.UpdateTask(t);
return dbMan.GetTask(t.Id);
}
DatabaseManager Methods
public void UpdateTask(Task task)
{
if (task.Id == 0)
{
throw new InvalidOperationException("Cannot update a task that has not yet been inserted.");
}
using (var connection = new SQLiteConnection(_connectionString))
{
connection.Open();
using (var cmd = new SQLiteCommand(connection))
{
var sql = @"UPDATE [Task]
SET
[enabled]=@enabled,
[description]=@description,
[duedate]=@duedate,
[priority]=@priority
WHERE rowid=@rowId";
// Build up the command and its parameters
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
cmd.Parameters.Add(new SQLiteParameter("@enabled", task.IsEnabled ? 1 : 0));
cmd.Parameters.Add(new SQLiteParameter("@description", task.Description));
cmd.Parameters.Add(new SQLiteParameter("@duedate", task.DueDate.Ticks));
cmd.Parameters.Add(new SQLiteParameter("@priority", (int)task.Priority));
cmd.Parameters.Add(new SQLiteParameter("@rowid", task.Id));
var result = cmd.ExecuteNonQuery();
Debug.WriteLine($"Command executed. {result} rows affected.");
}
}
}
public IList<Task> GetAllTasks()
{
using (var connection = new SQLiteConnection(_connectionString))
{
connection.Open();
using (var cmd = new SQLiteCommand(connection))
{
// Create the command
var sql = "SELECT rowid, * from [Task] ORDER BY [duedate] DESC, [priority] DESC";
cmd.CommandText = sql;
// Execute the command and build the resultant list
var reader = cmd.ExecuteReader();
var retList = new List<Task>();
while (reader.Read())
{
retList.Add(this.GetTaskFromReader(reader));
}
return retList;
}
}
}
public Task GetTask(int id)
{
using (var connection = new SQLiteConnection(_connectionString))
{
connection.Open();
using (var cmd = new SQLiteCommand(connection))
{
var sql = "SELECT rowid, * from [Task] WHERE rowid=@id";
cmd.CommandText = sql;
cmd.Parameters.Add(new SQLiteParameter("@id", id));
var reader = cmd.ExecuteReader();
// The query will return only one item, so read it into a new task.
reader.Read();
var task = this.GetTaskFromReader(reader);
return task;
}
}
}
private Task GetTaskFromReader(SQLiteDataReader reader)
{
var retId = Convert.ToInt32(reader["rowid"]);
var desc = reader["description"].ToString();
var date = new DateTime((long)reader["duedate"]);
var isEnabled = Convert.ToBoolean(reader["enabled"]);
var priority = (Priority)Enum.Parse(typeof(Priority), reader["priority"].ToString());
return new Task(retId, isEnabled, desc, date, priority);
}
Aucun commentaire:
Enregistrer un commentaire