Laden...

Warum sind Child-Properties trotz include in einer EFCore-Abfrage leer?

Erstellt von GeneVorph vor 3 Jahren Letzter Beitrag vor 3 Jahren 573 Views
G
GeneVorph Themenstarter:in
180 Beiträge seit 2015
vor 3 Jahren
Warum sind Child-Properties trotz include in einer EFCore-Abfrage leer?

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

H
48 Beiträge seit 2020
vor 3 Jahren

du kannst keine frontend modelle in der datenbank nutzen

und sollst das auch nicht
[Artikel] Drei-Schichten-Architektur

D
261 Beiträge seit 2015
vor 3 Jahren

Welche Version von EF Core benutzt du?

Edit:
Versuch auch mal deine Navigation Property nicht mit new() zu initialisieren.

F
10.010 Beiträge seit 2004
vor 3 Jahren

Eher keine ObservableCollection benutzen.
Die braucht man sowieso nicht im DAL

5.657 Beiträge seit 2006
vor 3 Jahren

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

G
GeneVorph Themenstarter:in
180 Beiträge seit 2015
vor 3 Jahren

OK, erst Mal vielen Dank für eure Antworten! Bevor ich im Einzelnen antworte ganz kurz zum Problem:

  • ich konnte es nun "lösen", indem ich eine foreach-Schleife nutze. Mein Code sieht nun so aus:
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

G
GeneVorph Themenstarter:in
180 Beiträge seit 2015
vor 3 Jahren

Welche Version von EF Core benutzt du?

Edit:
Versuch auch mal deine Navigation Property nicht mit new() 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!

F
10.010 Beiträge seit 2004
vor 3 Jahren

Und tu dir einen gefallen, lass das mit den Tutorials auf YT, da gibt es sehr wenig gute.

Channel9 ist die deutlich bessere Wahl.