Hallo,
ich versuche gerade EntityFramework 6 mit SQLite in meiner App zum Laufen zu bringen.
Ich habe dieses Tutorial als Grundlage genommen:
https://erazerbrecht.wordpress.com/2015/06/11/sqlite-entityframework-6-tutorial/
Ich bekomme aber einfach nicht bei New Connection SQLite zur Auswahl.
Ich habe die NuGetPakete installiert:
EntityFramework 6.1.3
System.Data.SQLite 1.0.105.1
System.Data.SQLite.Core 1.0.105.1
System.Data.SQLite.EF6 1.0.105.1
System.Data.SQLite.Linq 1.0.105.1
Ich habe das Paket von SQL herunter geladen:
sqlite-netFx451-setup-bundle-x86-2013-1.0.105.1.exe
und das Target Frameworka auf 4.5.1 gesetzt.
Ich weiß leider nicht, was ich übersehe.
Der Wizard gibt es in der identischen Form auch in neuen VS Versionen nicht mehr.
Es hat sich deutlich herausgestellt, dass die Umsetzung direkt im Code - Code First - viel effizienter ist.
Der Wizard legt eh nur den Connection String in der *.config an; arg viel mehr macht er nicht.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ok. Leider sind die meisten ausführlichen Tutorials und Code Schnipsel, die ich im Netzt zum Thema WPF und SQLite gefunden habe in Zusammenhang mit dem EntityFramework 6.
Momentan habe ich meine SQLite Operationen in einer Helfer Klasse, aber irgendwie sieht das ganze für mich "unelegant" aus.
In meinem MainViewModel nutze ich das ganze so (Beispiele):
SQLiteHelper sqlite = new SQLiteHelper();
if (!sqlite.CheckAdmin())
{
[...]
}
User login = sqlite.Login(Loginname, HelperClass.MD5Hash(Password));
Und mein SQLite Klasse sieht so aus:
class SQLiteHelper
{
private SQLiteConnection sqlConn;
private static string sqliteFile = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/resperLaMe.db"; // set folder for database
private static string sqlitePw = "dbpassword"; // set password for database
public SQLiteHelper()
{
// check if database file exist when not create with password
if (!File.Exists(sqliteFile))
{
sqlConn = new SQLiteConnection("Data Source=" + sqliteFile);
sqlConn.SetPassword(sqlitePw);
}
sqlConn = new SQLiteConnection("Data Source=" + sqliteFile + ";Password=" + sqlitePw); // connect to database
// create tables, when not exist
string query =
"CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY AUTOINCREMENT, 'login' TEXT, 'firstname' TEXT, 'lastname' TEXT, 'persid' TEXT, 'password' Text, 'role' INTEGER, 'first' INTEGER, 'active' INTEGER);" +
"CREATE TABLE IF NOT EXISTS userRights (id INTEGER PRIMARY KEY, 'lwe' INTEGER, 'lwa' INTEGER, 'lwb' INTEGER, 'lwi' INTEGER, 'mwe' INTEGER, 'mwa' INTEGER, 'mwb' INTEGER, 'mwi' INTEGER, 'vacc' INTEGER, 'vadr' INTEGER);" +
"CREATE TABLE IF NOT EXISTS admin ('password' Text);";
queryNon(query);
}
// check if admin password exist
public bool CheckAdmin()
{
sqlConn.Open();
var command = sqlConn.CreateCommand();
command.CommandText = "SELECT * FROM admin";
SQLiteDataReader reader = command.ExecuteReader();
bool rows = reader.HasRows;
sqlConn.Close();
return rows;
}
// login user
// if login doesnt match return an empty user
public User Login(string login, string pw)
{
User user = new User();
sqlConn.Open();
if (!login.Equals("Admin"))
{
var command = sqlConn.CreateCommand();
command.CommandText = "SELECT * FROM user LEFT JOIN userRights ON user.id = userRights.id WHERE user.login = '@login' AND user.password = '@password';";
command.Parameters.AddWithValue("@login", login);
command.Parameters.AddWithValue("@password", pw);
SQLiteDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
user.Id = reader.GetInt32(0);
user.Login = reader.GetString(1);
user.Role = reader.GetInt16(6);
break;
}
}
}
else
{
var command = sqlConn.CreateCommand();
command.CommandText = "SELECT * FROM admin WHERE admin.password = '@password'";
command.Parameters.AddWithValue("@password", pw);
SQLiteDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
user.Id = 0;
user.Login = "Admin";
user.Role = -1;
}
}
sqlConn.Close();
return user;
}
// methode for querys without response
private void queryNon(string query)
{
sqlConn.Open();
var command = sqlConn.CreateCommand();
command.CommandText = query;
command.ExecuteNonQuery();
sqlConn.Close();
}
}
Ja, das ist schon sehr unelegant. Im Falle des Klartext-Passwortes sogar fahrlässig.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ja, das ist schon sehr unelegant. Im Falle des Klartext-Passwortes sogar fahrlässig.
- Schau Dir den Repository Pattern an.
- Speicher Passwörter niemals im Klartext, sondern gesalzen (
> )- Verwende Dependency Injection und vermeide Magic Strings oder Hardcoded-Stuff wie DB-Namen.
- Erstelle Datenbanken besser mit Bibliotheken wie FluentMigrator.
- Bei Sqlite würde ich auch Dapper als MicroORM empfehlen.
Passwörter: Meine MD5 Methode aus den Anwendungsbeispiel:
User login = sqlite.Login(Loginname, HelperClass.MD5Hash(Password));
versieht das Passwort mit einem Salt.
Der Rest der Punkte sind für mich ehrlich gesagt böhmische Dörfer 😉 Da werde ich mich wohl noch weiter einlesen müssen.
Also ich habe mich jetzt durch alle möglichen Beispiele gewühlt, die ich mit Hilfe von Google und den Suchbegriffen "c# wpf sqlite" gefunden habe und bin bisher kaum auf aussagekräftige Beispiele gestoßen, die sich stark von meinem zur Zeit verwendeten Code unterscheiden.
Wäre es evtl. möglich mir in Bezug auf "Verwende Dependency Injection und vermeide Magic Strings oder Hardcoded-Stuff wie DB-Namen." Beispiele in Bezug auf meinen Code aufzuzeigen?
MD5 (vor allem ohne Salt) ist kein sicheres Verfahren. Bitte verwende Salting mit einem entsprechend sicheren Verfahren, zB SHA 512.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo resper,
Also ich habe mich jetzt durch alle möglichen Beispiele gewühlt, die ich mit Hilfe von Google und den Suchbegriffen "c# wpf sqlite" gefunden habe und bin bisher kaum auf aussagekräftige Beispiele gestoßen, die sich stark von meinem zur Zeit verwendeten Code unterscheiden.
Du musst dir immer vor Augen halten, dass Blogposts etc. die _direkte _Problemlösung auf dein Problem enthalten können. Sie sind aber selten zum copy/pasten geeignet und erklären alles andere drumherum. Somit findest du auf deinen gefundenen Artikeln zwar eine Lösung, die im besten Fall noch funktioniert, jedoch musst du sie selber in dein Programm integrieren und mit den genannten Stichworten verheiraten. Kein Artikel wird dir noch Repositories, DI etc. zusätzlich erklären, da es meistens in den gefundenen Sachen nicht darum geht.
Unter den genannten Stichworten findest du ebenfalls eine Menge Infos. Lies dich da mal ein und schau, in wie weit dir das helfen kann.
[Artikel] Drei-Schichten-Architektur
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Danke für die Tipps. Ich werde weiter versuchen mich zu belesen.