verwendetes Datenbanksystem: EntityFrameworkCore / SQLite
Hallo,
Ich habe in meiner wpf-Anwendung folgende Models:
public class SchoolClass : ISchoolClassData
{
[Required]
public int SchoolClassId { get; set; }
[Required]
public SchoolClassInternal SchoolClassInternals { get; set; } = new SchoolClassInternal();
}
public class SchoolClassInternal : ISchoolClassInternal
{
[Required]
public int SchoolClassInternalId { get; set;}
[Required]
[MaxLength(64)]
public string SchoolClassLabel { get; set; }
[MaxLength(64)]
public string SchoolClassLevel { get; set; }
[MaxLength(64)]
public string SchoolClassHead { get; set; }
public ObservableCollection<Student> ClassStudents { get; set; } = new ObservableCollection<Student>();
}
Wenn ich ein SchoolClass-Objekt erstelle und es an die SQLite-Datenbank übergebe, dann finde ich die übergebenen Daten dort wieder. Beim Lesen der Daten jedoch sind die Properties von SchoolClassInternals leer. Meine Methode:
public static List<SchoolClass> GetAllClasses()
{
List<SchoolClass> _entity = new List<SchoolClass>();
using (var context = new DataBaseContext())
{
if (context.SchoolClasses.Any())
{
_entity = context.SchoolClasses
.Include(c => SchoolClassInternals)
.ToList();
}
return _entity;
}
Es werden zwar die richtigen SchoolClass-Objekte zurückgegeben, deren SchoolClassInternals-Properties sind jedoch leer (SchoolClassInternalId, SchoolClassInternalLabel, SchoolClassInternalLevel, SchoolClassInternalHead).
Ich habe mal den UP-Part der Migration kopiert - soweit ich das interpretieren kann, wurden alle Indizes richtig zugeordnet
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Adresses",
columns: table => new
{
AdressId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Street = table.Column<string>(type: "TEXT", maxLength: 128, nullable: true),
PostalCode = table.Column<string>(type: "varchar(12)", maxLength: 10, nullable: true),
City = table.Column<string>(type: "TEXT", maxLength: 128, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Adresses", x => x.AdressId);
});
migrationBuilder.CreateTable(
name: "Educationals",
columns: table => new
{
EducationalId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
ClassLabel = table.Column<string>(type: "TEXT", maxLength: 64, nullable: false),
ClassLevel = table.Column<string>(type: "TEXT", maxLength: 64, nullable: true),
EducationalProgram = table.Column<string>(type: "TEXT", maxLength: 64, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Educationals", x => x.EducationalId);
});
migrationBuilder.CreateTable(
name: "Personals",
columns: table => new
{
PersonalId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
FirstName = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
LastName = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
FullName = table.Column<string>(type: "TEXT", maxLength: 128, nullable: true),
DateOfBirth = table.Column<string>(type: "varchar(15)", maxLength: 15, nullable: true),
Gender = table.Column<string>(type: "TEXT", maxLength: 20, nullable: true),
PhoneNumber = table.Column<string>(type: "varchar(128)", maxLength: 128, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Personals", x => x.PersonalId);
});
migrationBuilder.CreateTable(
name: "SchoolClassInternals",
columns: table => new
{
SchoolClassInternalId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
SchoolClassLabel = table.Column<string>(type: "TEXT", maxLength: 64, nullable: false),
SchoolClassLevel = table.Column<string>(type: "TEXT", maxLength: 64, nullable: true),
SchoolClassHead = table.Column<string>(type: "TEXT", maxLength: 64, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SchoolClassInternals", x => x.SchoolClassInternalId);
});
migrationBuilder.CreateTable(
name: "SchoolClasses",
columns: table => new
{
SchoolClassId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
SchoolClassInternalsSchoolClassInternalId = table.Column<int>(type: "INTEGER", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SchoolClasses", x => x.SchoolClassId);
table.ForeignKey(
name: "FK_SchoolClasses_SchoolClassInternals_SchoolClassInternalsSchoolClassInternalId",
column: x => x.SchoolClassInternalsSchoolClassInternalId,
principalTable: "SchoolClassInternals",
principalColumn: "SchoolClassInternalId",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Students",
columns: table => new
{
StudentId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
StudentPersonalPersonalId = table.Column<int>(type: "INTEGER", nullable: true),
StudentAdressAdressId = table.Column<int>(type: "INTEGER", nullable: true),
StudentEducationalEducationalId = table.Column<int>(type: "INTEGER", nullable: true),
SchoolClassInternalId = table.Column<int>(type: "INTEGER", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Students", x => x.StudentId);
table.ForeignKey(
name: "FK_Students_Adresses_StudentAdressAdressId",
column: x => x.StudentAdressAdressId,
principalTable: "Adresses",
principalColumn: "AdressId",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Students_Educationals_StudentEducationalEducationalId",
column: x => x.StudentEducationalEducationalId,
principalTable: "Educationals",
principalColumn: "EducationalId",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Students_Personals_StudentPersonalPersonalId",
column: x => x.StudentPersonalPersonalId,
principalTable: "Personals",
principalColumn: "PersonalId",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Students_SchoolClassInternals_SchoolClassInternalId",
column: x => x.SchoolClassInternalId,
principalTable: "SchoolClassInternals",
principalColumn: "SchoolClassInternalId",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_SchoolClasses_SchoolClassInternalsSchoolClassInternalId",
table: "SchoolClasses",
column: "SchoolClassInternalsSchoolClassInternalId");
migrationBuilder.CreateIndex(
name: "IX_Students_SchoolClassInternalId",
table: "Students",
column: "SchoolClassInternalId");
migrationBuilder.CreateIndex(
name: "IX_Students_StudentAdressAdressId",
table: "Students",
column: "StudentAdressAdressId");
migrationBuilder.CreateIndex(
name: "IX_Students_StudentEducationalEducationalId",
table: "Students",
column: "StudentEducationalEducationalId");
migrationBuilder.CreateIndex(
name: "IX_Students_StudentPersonalPersonalId",
table: "Students",
column: "StudentPersonalPersonalId");
}
Habe ich etwas offensichtliches übersehen?
Gruß
Vorph
du kannst keine frontend modelle in der datenbank nutzen
und sollst das auch nicht
[Artikel] Drei-Schichten-Architektur
Welche Version von EF Core benutzt du?
Edit:
Versuch auch mal deine Navigation Property nicht mit new()
zu initialisieren.
Eher keine ObservableCollection benutzen.
Die braucht man sowieso nicht im DAL
Habe ich etwas offensichtliches übersehen?
Ja. Du solltest dir mal ein Einführungs-Tutorial von EF Core anschauen, bevor du loslegst. Da ist alles erklärt, was du hier versuchst.
Weeks of programming can save you hours of planning
OK, erst Mal vielen Dank für eure Antworten! Bevor ich im Einzelnen antworte ganz kurz zum Problem:
public static List<SchoolClass> GetAllClasses()
{
List<SchoolClass> _entity = new List<SchoolClass>();
using (var context = new DataBaseContext())
{
if (context.SchoolClasses.Any())
{
_entity = context.SchoolClasses.Include(ci => ci.SchoolClassInternals).ToList();
foreach (SchoolClass sc in _entity)
{
sc.SchoolClassInternals = context.SchoolClassInternals.Where(s => s.SchoolClassInternalId == sc.SchoolClassId).FirstOrDefault();
}
}
return _entity;
}
Durch die Include-Methode wird (bzw. wurde auch vorher schon) das SchoolClassInternals-Property hinzugefügt - nur wurden seine Property-Daten nicht geladen. Ich dachte, das wäre mit Include abgehakt...
Und damit kommen wir schon zu
du kannst keine frontend modelle in der datenbank nutzen
und sollst das auch nicht
[Artikel] Drei-Schichten-Architektur
Können schon - aber es leuchtet ein, dass es eine schlechte Idee ist. Wird in der nächsten Überarbeitung behoben.
Welche Version von EF Core benutzt du?
Edit:
Versuch auch mal deine Navigation Property nicht mit new() zu initialisieren.
Version 5.0.0 --> habe new() beim Navigation-Property entfernt (es ändert aber nichts am eigentlichen Problem).
Eher keine ObservableCollection benutzen.
Die braucht man sowieso nicht im DAL
Auch richtig - ich dachte mir schon, dass mein Code derzeit höchst unsexy ist 😉 Ich versuche gerade alles, was ich online finden konnte (z. B. auf YouTube von Kanälen wie AngelSix, IAMTimCorey) aber auch zwei Udemy-Kursen und sämtlichen Blogs irgendwie sinnvoll zusammen zu tragen. Leider ist es nicht ganz einfach und nicht in ein paar Monaten machbar. Das wird wohl Jahre dauern, bis da wirklich "Profi-Code" drauß wird.
Leider verwenden viele Beispiele kein MVVM, andere pfeifen (aus Gründen der Einfachheit) auf DAL, eben um "nur mal kurz was zu zeigen" und dann muss man sich das aus unzähligen anderen Quellen zusammenstoppeln.
Ja. Du solltest dir mal ein Einführungs-Tutorial von EF Core anschauen, bevor du loslegst. Da ist alles erklärt, was du hier versuchst.
Kennst du denn ein gutes? Ich habe eines auf Udemy gefunden v. Mosh Hamedami, der auch auf YouTube aktiv ist. Es ist natürlich nahezu unmöglich zu sagen ob es denn "gut" ist (dazu hätte ich ja andere noch im Vergleich sehen müssen). Seine Schwäche ist, dass relationale Datenbezüge halt nur angekrazt werden - da konnte ich bei Tim Corey mehr finden; der übt aber eher Kritik an EF und so versuche ich halt das Beste aus beiden Welten zu generieren.
Gruß vorph
Welche Version von EF Core benutzt du?
Edit:
Versuch auch mal deine Navigation Property nicht mitnew()
zu initialisieren.
Halt! Ich nehme alles zurück und behaupte das Gegenteil! Gendau DAS war scheinbar das Problem - ich hatte es nur beim ersten Mal mit der falschen Methode getestet!
Nächster Task: eine gescheite DataAccessLayer...
vielen Dank!
Und tu dir einen gefallen, lass das mit den Tutorials auf YT, da gibt es sehr wenig gute.
Channel9 ist die deutlich bessere Wahl.