I'm using SQLite in my app (through the System.Data.SQLite package). Right now all the insertion, queries, and other operations are done by sending commands using strings, for example:
SQLiteCommand command = new SQLiteCommand(comStr, db);
where comStr - is a string variable holding the command.
Are there other options I can use instead of strings? Or are strings the proper way one should use when handling SQL queries from .NET?
The problem is that using strings can get rather messy, for example I have some filters that the user can set. Manipulating the command using the strings - although works - feels to me very brittle:
public string GetFilterString()
{
string fil1 = "";
string fil2 = "";
string fil3 = "";
string fil4 = "";
// filter by time
switch (WithinTimeBtnStatus)
{
case WithinTime.All:
break;
case WithinTime.Hour:
string minusHour = (DateTime.Now - new TimeSpan(0, 1, 0, 0)).ToString("yyyy-MM-dd HH:mm:ss.fff");
fil1 = $" timestamp >= datetime('{minusHour}')";
break;
case WithinTime.Day:
string minusDay = (DateTime.Now - new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd HH:mm:ss.fff");
fil1 = $" timestamp >= datetime('{minusDay}')";
break;
case WithinTime.Week:
string minusWeek = (DateTime.Now - new TimeSpan(7, 0, 0, 0)).ToString("yyyy-MM-dd HH:mm:ss.fff");
fil1 = $" timestamp >= datetime('{minusWeek}')";
break;
}
// filter by extension
for (int i = 0; i < FilteredExt.Count; i++)
{
fil2 += " ext != '" + FilteredExt[i] + "'";
if (i < FilteredExt.Count - 1)
fil2 += " and";
}
// filter by process
if (_processFilterSelected.ToLower() != "all" && _processFilterSelected != "")
{
fil3 = $" proc == '{_processFilterSelected}'";
}
// filter by File Operation
if (_FileOperationFilterSelected.ToLower() != "all" && _FileOperationFilterSelected != "")
{
FileOperation fo = Converters.StringToFileOperation(_FileOperationFilterSelected);
switch (fo)
{
case FileOperation.Deleted:
fil4 = " oper == 'DELETED'";
break;
case FileOperation.Renamed:
fil4 = " oper == 'RENAMED'";
break;
case FileOperation.Modified:
fil4 = " oper == 'MODIFIED'";
break;
}
}
string fil = "";
var tmp = new[] { fil1, fil2, fil3, fil4 };
foreach (var t in tmp)
{
if (t != "")
{
fil += " and" + t;
}
}
return fil;
}
Since I didn't get a satisfactory answer, I will post what I ended up doing. I think this probably a decent way, but there might be other better ways to achieve what I was looking for (using LINQ type syntax on my DB, instead of using strings containing queries).
Also - I am not sure this is faster then simply using query strings.
TL;DR: Use SQLite.CodeFirst + EntityFramework.
(On a side note, it might be possible to use LINQ to SQL instead of EntityFramework, but not sure if also in a CodeFirst approach. Will update once I tried and tested this).
First thing, you need to add these packages:
And finally if you're starting from code (like I did), you'll also need
The next thing to do is set up the connection string in app.config.
(On a side note - There seems to be tons of bugs with specifying the providers, which uninstalling and reinstalling the packages above seems to fix. I'm not so sure about the logic behind removing and adding, and invariant names - if you care for what I wrote, it's this:
)
The connection string should specify a name, and at least a path to where your DB file should be located. You can also use relative paths that you later define in the code (by using the |DataDirectory| syntax):
The next step, if you're doing Code-First, is creating a new class that will be your model, this is basically using the SQLite.CodeFirst package:
}
You can read more about it here.
And that's basically it with the preparations.
(On a side note, if you want to change the relative path to the DB file from code behind, you'll need to write:
)
Now you can just use it. The basic syntax is very simple, you just use:
So Select:
If you want to Insert:
If you want to still use string queries:
Some important things to remember:
Context.SaveChange()
in the end (you don't need this for ExecuteSqlCommand)So the example in the question GetFilterString changes to: