verwendetes Datenbanksystem: SQLite
Hallo, ich mache gerade meine ersten versuche mit SQLite und EFCore in C#.
Ich habe ein kleines Tool geschrieben, mit dem 3 Tabellen gefüllt werden.
Die Datenbank ->
public class DBContext : DbContext
{
public DbSet<PLCTyp> PLCSets { get; set; }
public DbSet<DBTyp> DbSets { get; set; }
public DbSet<VarTyp> VarSets { get; set; }
private static bool _created = false;
public DBContext()
{
if (!_created)
{
_created = true;
// Database.EnsureDeleted();
Database.EnsureCreated();
}
}
public void ClearDatabase()
{
Database.EnsureDeleted();
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=MyDatabase.sqlite");
}
public class PLCTyp
{
public int id { get; set; }
public string name { get; set; }
public string ip { get; set; }
public string target { get; set; }
public int cycle { get; set; }
}
public class DBTyp
{
public int id { get; set; }
public List<PLCTyp> plcId { get; set; }
public string name { get; set; }
public int adress { get; set; }
public int offset { get; set; }
public int lengh { get; set; }
}
public class VarTyp
{
public int id { get; set; }
public List<DBTyp> dbId { get; set; }
public string name { get; set; }
public int offset { get; set; }
public int lengh { get; set; }
public int varId { get; set; }
}
Hier eine Abfrage
List<DBTyp> getDBbyPlc(PLCTyp plc)
{
try
{
using (var db = _db)
{
var dbs = db.DbSets
.Where(b => b.plcId.Contains(plc)).
ToList();
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return null;
}
Ist das so richtig? Ich hab zu primary/ foreign key relativ wenig gefunden.
Zur Erklärung in der
Tabelle 1 befinden sich die Verbindungen "PLCTyp"
Tabelle 2 befinden sich die Streams "DBTyp" (hat nichts mit der Datenbank zu tun das heißt nur so)
Tabelle 3 sind die Datentypen die mit gemappt werden damit ich von dem Stream zu brauchbare Variablen komme "VarTyp".
Der Tag war lange und ich glaube ich hab einen großen Denkfehler vor mir....
Schon mal vielen Dank
Gruß
Nenn Dein DB Context richtig. DBContext : DbContext
erkennt ja keiner den Unterschied und führt nur zu Verwirrung.
Wenn Dein Tool PlcTool heisst, dann nenn den Context eben PlcToolDbContext - so ist es gedacht.
Namen von Variablen und Klassen sollen immer Aussagen, was sie wirklich sind. =)
Halte Dich an die Naming Guidelines von C#
[Artikel] C#: Richtlinien für die Namensvergabe
Deine Abfrage mit dem Ensure macht wenig Sinn.
Ensure erstellt die Datenbank ohnehin nur, wenn sie nicht existiert.
Ergo brauchst Du die Abfrage überhaupt nicht.
Die Exception zu fangen und dann in Exception nur die Message zu legen führt dazu, dass Dir der gesamte StackTrace verloren geht.
Hier an der Stelle die Exception überhaupt nicht fangen - macht kein Sinn
ToList sollte man nur zurück geben, wenn man auch wirklich alle Inhalte dazu laden will.
ToList führt immer den Query aus (Query Materializing) - sollte also gerade bei großen Resultaten vermieden werden
Schau Dir den Repository Pattern an und dazu wie die Verbindung in einem Repository gehalten wird.
Dein Code ist so nicht testbar (und es macht wenig sinn, dass in jeder Get-Abfrage die Verbindung aufgebaut wird; macht es unnötig langsam)
Relations würde ich immer mit Hilfe der FluentAPI umsetzen; das hilft sehr schnell um potentielle Denkfehler zu finden. 👍
Ansonsten sehe ich keine Frage; und der Code ist ja sehr ähnlich zum offiziellen EF Core Beispiel.
Ob das funktioniert kannst Du ja selbst ausprobieren 😉
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Naja bitte nicht gleich so streng, Ich versuche mich ein wenig einzuarbeiten und kopiere einiges zusamen um mal was zu testen.
Ich werde mich bemühen!
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DBTyp>()
.HasOne(p => p.PLCTyp)
.WithMany(b => b.DbSets)
.HasForeignKey(p => p.PLCTypId);
modelBuilder.Entity<VarTyp>()
.HasOne(p => p.DBTyp)
.WithMany(b => b.VarSets)
.HasForeignKey(p => p.DBTypId);
}
}
public class PLCTyp
{
public int PLCTypId { get; set; }
public string name { get; set; }
public string ip { get; set; }
public string target { get; set; }
public int cycle { get; set; }
public List<DBTyp> DbSets { get; set; }
}
public class DBTyp
{
public int DBTypId { get; set; }
public string name { get; set; }
public int adress { get; set; }
public int offset { get; set; }
public int lengh { get; set; }
public int PLCTypId { get; set; }
public PLCTyp PLCTyp { get; set; }
public List<VarTyp> VarSets { get; set; }
}
public void InsertDB( PLCTyp pLCTyp, DBTyp dBTyp)
{
try
{
using (var db = new DBContext())
{
var plc = db.PlcSets.Where(p => p.PLCTypId == pLCTyp.PLCTypId).Single();
plc.DbSets.Add(dBTyp);
db.SaveChanges();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
aktuell hänge ich hier, ich würde gerne in PLCSets einen Eintrag updaten aber irgendwie bekomme ich das nicht zu stande
Mir fällt ständig ein null ref Exception.
In den EF Core Beispielen wird das auch mit dem inlucde gemacht. Das fehlt bei mir komplett.
Weiß wer rat?
Wenn du die Navigation Property als virtual deklarierst kann EF das nachladen für dich übernehmen:
http://www.entityframeworktutorial.net/lazyloading-in-entity-framework.aspx
Schau Dir auch bitte den Repository Pattern an.
Man sollte es tunlichst vermeiden, in einer ausführenden DB-Methode (hier Insert und Get) jedes mal die Datenbankverbindung neu zu erstellen; macht wenig bis keinen Sinn.
Zudem ist
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return null;
kein valides Exception Handling.
Das unterdrückt alles, was man nicht unterdrücken sollte. ⚠
Es gibt hier keine Notwendigkeit im DB-Layer eine Exception zu fangen - und verfälscht sogar den StackTrace. 😉
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code