Laden...

Wie kann ich einen 1:N Datensatz im Entity Framework Core auslesen?

Erstellt von Taucher vor 3 Jahren Letzter Beitrag vor 3 Jahren 2.038 Views
T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren
Wie kann ich einen 1:N Datensatz im Entity Framework Core auslesen?

verwendetes Datenbanksystem: <SqlServer 2008>
Hallo Leute,
ich bin gerade daran mir das Entity-Framework bei .Net Core einzuverleiben, und habe da gleich ein Problem mit einer 1:n Beziehung.
Und zwar habe ich folgende Tabellen:


TB_Account
--------------
AccountId
LoginName
Password

TB_AccountAccountData
----------------------------
AccountId
AccountDataId

TB_AccountData
---------------------
AccountDataId
EmailAddress
ModuleId
...

Meine Klasse für den DbContext sieht folgendermaßen aus:


internal class LoginSystemContext : DbContext
    {
        public DbSet<TB_Account> Accounts { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder options)
                => options.UseSqlServer("Data Source=LoginSystem.db");
    }

und die Klasse für das Account-Modell:


internal partial class TB_Account
	{
		#region properties...
		public int Id { get; set; }
		public string LoginName { get; set; }
		public string Password { get; set; }
		public ICollection<TB_AccountData> AccountData { get; set; }
		#endregion
	}

Wenn ich das hier: Erste Schritte mit EF Core richtig verstanden habe, dann reicht die ICollection aus, um auf die Werte einer 1:n Beziehung zugreifen zu können.
Jetzt weiß ich nicht wie ich das machen kann, um einen mir einen Datensatz anzeigen zu lassen wo folgende Kriterien erfüllt sein müssen:
-> LoginName und EmailAddress und ModuleId
vorhanden sind.
Wenn ichs richtig gelesen habe, dann brauche ich dafür den Join-Ausdruck, aber ich weiß nicht genau wie ich das Anstellen soll.
Kann mir da bitte jemand in meinem Beispiel helfen? Dann verstehe ich das wahrscheinlich auch besser als mit ähnlichen Beispielen die man so findet.

16.807 Beiträge seit 2008
vor 3 Jahren

Wenn ichs richtig gelesen habe, dann brauche ich dafür den Join-Ausdruck, aber ich weiß nicht genau wie ich das Anstellen soll.

Siehe hier: Complex Query Operators

"Besser" ist es aber, wenn Du Dir dafür eine eigene Abfrage-Klasse baust; heute heissen die Keyless Entities, früher Query Entities.
Keyless Entity Types.

Damit vermeidest Du den unnötigen Umgang mit anonymen / dynamischen Typen im Result, hast nen übersichtlicheren Code, bist Typsicher unterwegs und für EF ist das performanter.

Noch einfacher (aber mit externer Abhängigkeit) ist hier AutoMapper.
AutoMapper kann von Queries auf Abfragetypen projizieren: AutoMapper ProjectTo

Du musst dann für den Abfragetyp nur noch ein Profil erstellen.
Das Profil ist am Ende das, aus dem nachher automatisch ein Join generiert wird.

Ich verwende letzteres exzessiv; u.a. auch im neuen Forencode von mycsharp.

Ein Profil kann dabei folgendermaßen aussehen:

    public class UserProfileProjectionProfile : AutoMapper.Profile
    {
        public UserProfileProjectionProfile()
        {
            CreateMap<UserAccountEntity, UserProfileProjection>()

                .ForMember(p => p.Profile,
                    opt => opt.MapFrom(e => e))

                .ForMember(p => p.Avatar,
                    opt=> opt.MapFrom(e => e.Avatar))

                .ForMember(p => p.ForumStats,
                    opt=> opt.MapFrom(e => e))

                .ForMember(p => p.LatestActivity,
                    opt => opt.MapFrom(e => e))
        }
    }

Wie man sieht sind es 4 Eigenschaften, die von UserAccountEntity auf UserProfileProjection übertragen werden.
Profile, Avatar und ForumStats sind dabei eigene Projektionen, was unter der Haube entsprechende Joins sind.

PS: Datenbanken besitzen wie Quellcode auch Empfehlungen:

  • Tabellen im Plural
  • Keine Präfixe oder Suffixe
T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Hallo Abt,

vielen Dank für deine ausführliche Antwort.
Wenn ich damit dann Schwierigkeiten habe, dann melde ich mich wieder.

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Also, ich komme überhaupt nicht weiter. Ich habe jetzt mal versucht, das Beispiel von:
Beziehungen-EF Core
in mein Beispiel umzusetzen, und zwar folgendermaßen:


public class RelationTestContext : DbContext 
    {
        public DbSet<Account> Accounts { get; set; }
        public DbSet<AccountData> AccountDatas { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<AccountData>()
                .HasOne(accountData => accountData.Account)
                .WithMany(account => account.AccountData);

            modelBuilder.Entity<AccountData>()
                .HasKey(s => s.AccountDataId);

            modelBuilder.Entity<Account>()
                .HasKey(s => s.AccountId);
        }
    }
    public class Account
    {
        public int AccountId { get; set; }
        public string LoginName { get; set; }

        public List<AccountData> AccountData { get; set; }
    }

    public class AccountData
    {
        public int AccountDataId { get; set; }
        public string EmailAddress { get; set; }
        public int ModuleId { get; set; }

        public Account Account { get; set; }
    }

    public class EntityTest
    {
        public void MyTestMethod()
        {
            List<AccountData> accountDatas = new List<AccountData>();
            accountDatas.Add(new AccountData() { AccountDataId = 1, EmailAddress = "email1", ModuleId = 1, Account = new Account() { AccountId = 1, LoginName = "Name1", AccountData = accountDatas } });
            accountDatas.Add(new AccountData() { AccountDataId = 2, EmailAddress = "email1", ModuleId = 2, Account = new Account() { AccountId = 1, LoginName = "Name1", AccountData = accountDatas } });

            List<Account> accounts = new List<Account>();
            accounts.Add(new Account() { AccountId = 1, LoginName = "Name1", AccountData = accountDatas });

            accountDatas = new List<AccountData>();
            accountDatas.Add(new AccountData() { AccountDataId = 3, EmailAddress = "email2", ModuleId = 1, Account = new Account() { AccountId = 1, LoginName = "Name2", AccountData = accountDatas } });
            accountDatas.Add(new AccountData() { AccountDataId = 4, EmailAddress = "email2", ModuleId = 2, Account = new Account() { AccountId = 1, LoginName = "Name2", AccountData = accountDatas } });

            accounts = new List<Account>();
            accounts.Add(new Account() { AccountId = 1, LoginName = "Name2", AccountData = accountDatas });


            using (RelationTestContext context = new RelationTestContext())
            {
                var result = (
                             from account in accounts
                             join accountData in accountDatas
                             on account equals accountData.Account
                             where accountData.EmailAddress == "email2"
                             && accountData.ModuleId == 2
                             select new { Account = account }
                             ).FirstOrDefault();

                var result2 = (
                                from account in accounts
                                join accountData in accountDatas
                                on account equals accountData.Account
                                select new { Account = account }
                                ).ToList();
                
            }
        }
    }

result1 ist null, und result2 hat keine Datensätze...

Ich habe keine Ahnung was und wieso das nicht funktioniert...
Wenn jemand Lust dazu hat mir weiterzuhelfen, dann freue ich mich von ihm/ihr zu hören/lesen.

4.931 Beiträge seit 2008
vor 3 Jahren

Hallo,

mit

on account equals accountData.Account

vergleichst du die Referenzen, und da du verschiedene per new erzeugte Account-Objekte verwendest, kann der Vergleich so nicht klappen.
Versuche mal


on account.AccountId equals accountData.Account.AccountId

Zum Test erzeuge mal nur genau 1 Account-Objekt und benutze dieses in den Listen-Objekten (mit deiner Original Linq-Abfrage).
Bei Datenbankenzugriffen solltest du dich aber nicht darauf verlassen, daß du bei mehrfachem Zugriff immer das selbe (gecachete) Objekt zurückerhältst.

W
955 Beiträge seit 2010
vor 3 Jahren

Wieso ist die Beziehung Account :: AccountData n:m? Warum ist da AccountAccountData dazwischen? Du drückst aus dass es mehrere User gibt die sich eine E-Mailadresse teilen. Wenn du das nicht brauchst kannst du die Beziehung zu 1:n vereinfachen und dir den Tanz sparen.

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Th69

on account.AccountId equals accountData.Account.AccountId

Danke, daran lags!

witte

Wenn du das nicht brauchst kannst du die Beziehung zu 1:n vereinfachen und dir den Tanz sparen.

Ich versuche eine 1:n Beziehung zu machen. Ein Account kann mehrere AccountData haben.
Mach ich das hier nicht??? Oh man...

W
955 Beiträge seit 2010
vor 3 Jahren

Nein, das sind zwei 1:n die zusammen n:m ergeben. Die Linktabelle ist überflüssig.

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Jetzt versteh ich nur noch Bahnhof...
Laut dem hier: EF-Core Beziehungen
ist das doch eine 1:n Beziehung. Oder nicht?
Wie er in die Referenztabelle die Werte schreibt, ist mir allerdings noch ein Rätsel...
Muss ich dann die Referenztabelle mit anlegen?

W
955 Beiträge seit 2010
vor 3 Jahren

Du hast drei Tabellen
* TB_Account
* TB_AccountAccountData
* TB_AccountData
TB_AccountAccountData ist eine Link-Tabelle welche eine n:m-Beziehung von TB_Account und TB_AccountData abbildet. Meine Frage war gewesen ob es so gewollt ist, das TB_AccountData zu mehreren TB_Account zugeordnet werden kann.

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Ja, das ist so gewollt.
Ein Account kann einenn oder mehrere AccountDaten haben.

W
955 Beiträge seit 2010
vor 3 Jahren

Sorry, aber du musst mal versuchen genau zu lesen sonst wird das mit der Softwareentwicklung nichts. Die Frage war ob ein AccountData-Objekt mehreren Accounts zugeordnet werden kann.

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Taucher

Ich versuche eine 1:n Beziehung zu machen. Ein Account kann mehrere AccountData haben.

16.807 Beiträge seit 2008
vor 3 Jahren

Sorry, aber Du bastelst da einfach vor Dich hin.

Nimm Dir doch mal nen halben Tag Zeit für die EF Dokumentation und les sie durch.
So wird das im Chaos enden. Mit Anlauf und Vollgas. Du musst erstmal die Basics verstehen; angefangen bei der Modellierung und den Anforderungen.

Ganz davon abgesehen: im Jahr 2020 noch nen eigenes Loginsystem (mit Passwort offenbar im Klartext!) zu "basteln"....und das auch noch mit nicht mal Basis-Wissen; vielleicht eine nicht ganz so gute Idee 😉

Bei so einem Vorgehen leider nur die Frage der Zeit, bis es knallt.
Muss man so ehrlich leider sagen, sorry.

Und was Witte Dir gesagt hat: Im Eingangspost sprichst Du von 1:n - Dein "XML Code" zeigt aber n:m über 3 Tabellen. Was denn nun?
Dann wiederum hast Du plötzlich doch 1:n Code mit zwei Tabellen - und keiner versteht mehr was Du da eigentlich machst oder willst; vermutlich Du selbst nicht.

Ich versuche eine 1:n Beziehung zu machen. Ein Account kann mehrere AccountData haben.

Du musst den Satz zuende sprechen.

Ja, ein Account kann mehrere AccountData haben. Und AccountData?
So ist der Satz nicht zuende und wir können nicht hellsehen.

Der Relationssatz beschreibt alle beinhaltende Entitäten, zB
_Account hat mehrere AccountData; AccountData hat einen Account = 1:n _
_Account hat mehrere AccountData; AccountData hat mehrere Accounts = n:m mit noch erforderlicher Mapping Tabelle _

Laut dem Tabellenaufbau im Eingangspost kann ein AccountData eben mehrere Accounts haben => n:m

Daher auch die Verwirrung in dem Thread.

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Das Passwort ist natürlich nicht im Klartext abgespeichert, das versteht sich von selbst.
Ich habe nur durch das Beispiel mit den Klassen Account und AccountData versucht nachzustellen, es im EF-Core nachzustellen, auf einfache Weise, da die linq-Abfragen nicht (mehr) funktioniert haben, die ich im Ef6 verwendet habe.. Da ging ja alles Problemlos. Quasi zur Verständnis. Hat aber nicht funktioniert wie man sieht...
Ich mach mit C# seit 2008 rum, und ich weiß, das ich in einer Firma war, wo Fortbildung nur ein Traum war, und Freizeit um das zu tun, ja, da hätten wir wohl 10 Tage die Woche gebraucht...
Das ich in C# Defizite habe, das muss mir keiner sagen, den davor habe ich in PHP programmiert. Da ist das alles anders. Summa Sumarum, ist es bei mir einfach so, das ich eine Erklärung für "Doofe" brauche. Denn ich ich bin sicherlich keiner der das nicht versteht, sondern jemand, der ein realistisches Beispiel für das Problem braucht, was er einfach hat. Und die Hilfe zur Selbsthilfe, bringt mir oftmals nix.
Und ja, ich habe Druck im Nacken, wo ich mir überlege, Datenbankfunktionen zu nehmen, wenn das auch nicht zu kompliziert ist in .net core, oder eben auf vorherige Technologien zurückzugreifen.

16.807 Beiträge seit 2008
vor 3 Jahren

Ist ja alles kein Thema; muss man ja nur lernen. Aber Dein aktueller Ansatz bringt Dir nur Probleme. Das wird knallen, und am Ende hast nichts davon; außer Ärger.
Aber ja, dafür muss man sich Zeit nehmen - das kommt nicht von allein 😉

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

So, ich denke mal dass ich einen Schritt weiter gekommen bin.
Ich habe mir die Modelle mal von Entity selbst erstellen lassen, um zu sehen wie die das machen.
Daraus habe mir folgendes Beispiel zusammengestellt:


internal class TB_Mothers
    {
        public TB_Mothers()
        {
            this.Children = new HashSet<TB_Children>();
        }
        public int MotherId { get; set; }
        public string MotherName { get; set; }
        public ICollection<TB_Children> Children { get; set; }
    }

internal class TB_MothersChildren
    {
        public int MotherId { get; set; }
        public int ChildrenId { get; set; }
        public virtual TB_Mothers Mothers { get; set; }
        public virtual TB_Children Children { get; set; }
    }

internal class TB_Children
    {
        public int ChildrenId { get; set; }
        public string ChildName { get; set; }
        public TB_Mothers Mothers { get; set; }
    }

internal class MotherChildrenContext : DbContext
    {
        public virtual DbSet<TB_Mothers> TB_Mothers { get; set; }
        public virtual DbSet<TB_MothersChildren> TB_MothersChildren { get; set; }
        public virtual DbSet<TB_Children> TB_Children { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
                optionsBuilder.UseSqlServer("server=.;database=Test;trusted_connection=true;");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TB_Mothers>
                (
                    entity => 
                    {
                        entity.HasKey(s => s.MotherId);
                        entity.ToTable("TB_Mothers");
                        entity.HasMany(s => s.Children)
                                .WithOne(s => s.Mothers);
                        entity.Property(s => s.MotherName)
                                .IsRequired()
                                .HasMaxLength(50);
                        entity.HasIndex(s => s.MotherName)
                                .HasName("UQ_TB_Mothers_MotherName")
                                .IsUnique();
                    }
                );

            modelBuilder.Entity<TB_MothersChildren>
                (
                    entity =>
                    {
                        entity.HasKey(s => new { s.MotherId, s.ChildrenId });
                        entity.ToTable("TB_MothersChildren");
                        entity.HasOne(s => s.Mothers)
                                .WithMany()
                                .HasForeignKey(s => s.MotherId)
                                .OnDelete(DeleteBehavior.ClientSetNull)
                                .HasConstraintName("FK_TB_MothersChildren_TB_Mother");
                        entity.HasOne(s => s.Children)
                                .WithMany()
                                .HasForeignKey(s => s.ChildrenId)
                                .OnDelete(DeleteBehavior.ClientSetNull)
                                .HasConstraintName("FK_TB_MothersChildren_TB_Children");
                                
                    }
                );

            modelBuilder.Entity<TB_Children>
                (
                    entity =>
                    {
                        entity.HasKey(s => s.ChildrenId);
                        entity.ToTable("TB_Children");
                        entity.Property(s => s.ChildName)
                                .IsRequired()
                                .HasMaxLength(50);
                    }
                );
        }
    }

Jetzt habe ich es geschafft, mir die Abfrage so zusammenzustellen, dass ich zumindest mal Daten bekomme. Und zwar so (eigentlich 1:1 wie in Sql):


var result = (
                                    from mothers in context.TB_Mothers
                                    join motherschildren in context.TB_MothersChildren
                                    on mothers.MotherId equals motherschildren.MotherId
                                    join children in context.TB_Children
                                    on motherschildren.ChildrenId equals children.ChildrenId
                                    select new TB_Mothers { MotherName = mothers.MotherName, MotherId = mothers.MotherId }
                                ).ToList();

Hier habe ich allerdings das Problem, das ich nicht weiß, wie ich das Laden der zugehörigen Daten mit include() integrieren kann.

Allerdings bringt mir diese Abfrage:


var result3 = context.TB_Mothers
                                    .Include(m => m.Children)
                                    .ToList();

auch nicht das gewünschte Ergebnis. Denn die ICollection Children hat keinen Eintrag obwohl welche vorhanden sind.
Laut der Doku hier: Laden zugehöriger Daten sollte es aber funktionieren.
Fehler im Modell???

Spaßeshalber habe ich dann mal versucht den Join in Lambda zu schreiben, wo es aber knallt:


var result2 = context.TB_Mothers
                                            .Join
                                            (
                                                context.TB_MothersChildren
                                                , m => m.MotherId
                                                , mc => mc.MotherId
                                                , (m, mc) => new { TB_Mothers = m, TB_MothersChildren = mc }
                                            ).Join
                                            (
                                                context.TB_Children
                                                , mc => mc.TB_MothersChildren.ChildrenId
                                                , c => c.ChildrenId
                                                , (mc, c) => new { TB_Children = c }
                                            ).ToList();

Was mache ich falsch bzw. wo liegt der Fehler?

16.807 Beiträge seit 2008
vor 3 Jahren

Also ich kapier nicht was Du willst.

Du hast wieder eine n:m Relation der Modelle gebastelt (die in der Implementierung aber so auch nicht funktionieren kann, so oder so), sprichst aber womöglich weiterhin von 1:n. Selbst die Bezeichnung "Mutter-Kind" suggeriert 1:n - aber Dein Code zeigt halt m:n.
Eine Mapping-Tabelle (hier TB_MothersChildren) brauchst Du für 1:n jedenfalls nie.

Und wie Du mit virtual um Dich wirfst hab ich die starke Vermutung, dass Du nicht weißt, was es tut, oder?

Was hast Du vor?
Ich glaub einfach, dass Dir massiv die Basics fehlen und daher es zu solchen Missverständnissen und Ergebnissen kommt.

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Hm, ich versuche eine 1:n Beziehung darzustellen. Ich habe laut Doku schon gesehen, dass dort immer nur 2 Klassen verwendet werden. Für das Beispiel hier dann eben in der Mother-Klasse die Children-Collection, und dann in der Children-Klasse nochmal die Eigenschaft der Mutter.
Aber ich habe dann aber das Problem, dass wenn ich mir alle Mütter anzeigen lassen will, die als Kind, z.B. "Karin" haben, ich von der Abfrage her nicht hinkomme, die where-Klausel auf die Children-Klasse zu machen.

Wieso nehme ich 3 Klassen? Wie bereits erwähnt, habe ich mir von Entity, durch das Reverse-Enginering, die Modelle mal erstellen lassen, um zu sehen, wie die das machen. Und die nehmen da 3 Klassen. Daher die Klasse zur Normalisierung. Auch die virtuals habe ich von dort übernommen.

Ich möchte einfach die 1:n Beziehung haben, wo ich dann auch die where-Klausel auf die Children-Klasse machen kann.

In Sql ist das ja recht einfach, aber irgendwie drehe ich mich jetzt da voll im Kreis.

Das ist wahrscheinlich voll simpel, und ich renne da grad voll in die falsche Richtung...

5.657 Beiträge seit 2006
vor 3 Jahren

Hm, ich versuche eine 1:n Beziehung darzustellen. Ich habe laut Doku schon gesehen, dass dort immer nur 2 Klassen verwendet werden. Für das Beispiel hier dann eben in der Mother-Klasse die Children-Collection, und dann in der Children-Klasse nochmal die Eigenschaft der Mutter.

Warum machst du es dann nicht so?

Aber ich habe dann aber das Problem, dass wenn ich mir alle Mütter anzeigen lassen will, die als Kind, z.B. "Karin" haben, ich von der Abfrage her nicht hinkomme, die where-Klausel auf die Children-Klasse zu machen.

var mothersOfKarins = context.Mothers.Where(m => m.Children.Any(n => n.FirstName == "Karin"));

Wieso nehme ich 3 Klassen? Wie bereits erwähnt, habe ich mir von Entity, durch das Reverse-Enginering, die Modelle mal erstellen lassen, um zu sehen, wie die das machen. Und die nehmen da 3 Klassen. Daher die Klasse zur Normalisierung. Auch die virtuals habe ich von dort übernommen.

Dann war es ein Beispiel für eine n:m-Beziehung.

Weeks of programming can save you hours of planning

16.807 Beiträge seit 2008
vor 3 Jahren

Wieso nehme ich 3 Klassen? Wie bereits erwähnt, habe ich mir von Entity, durch das Reverse-Enginering, die Modelle mal erstellen lassen, um zu sehen, wie die das machen. Und die nehmen da 3 Klassen.

Sorry, was Du gemacht hast ist kein Reverse Engineering sondern blind im Dunkel stochern; sorry für die direkten Worte.
Das hat mit Reverse Engineering nichts, aber auch gar nichts zutun. Nicht mal Ansatzweise.

Was Du willst kannst Du einfach 1:1 aus der Doku anhand des Blogbeispiels kopieren.


// Das Code Beispiel hält sich an alle namentlichen Konventionen in EFCore.
// Ein manuelles Mapping ist zwar empfohlen; aber durch das Einhalten der Konventionen kein Muss.
    public class Mother
    {
        public int MotherId { get; set; } // PK
        public ICollection<Child> Childs { get; set; }
    }

    public class Child
    {
        public int ChildId { get; set; } // PK

        public Mother Mother { get; set; }
        public int MotherId { get; set; } // FK
    }

Das ist eine einfache 1:n Relation zwischen Mother und Child.

Die Childs bekommst Du entweder anhand der Collection, wenn Du die Mother schon hast oder anhand der MotherId.

Daher die Klasse zur Normalisierung.

Das ist keine Normalisierung, sondern ein Mapping für eine n:m Relation; eine Hilfstabelle.
Normalisierungen in SQL ist was anderes.

T
2.219 Beiträge seit 2008
vor 3 Jahren

Scheinbar hast du dir die Doku selbst nicht gründlich durchgelesen.
In den Code Beispielen, werden deine Joins bereits über Include umgesetzt.
Du kannst also, wie auch Abt schon sagt, die Zwischenklasse sparen.

In EF kannst du doch ganz einfach über Where dann die Daten filtern, weshalb mir nicht klar ist, waru du solch eine Lösung gebastelt hast.
Ebenfalls solltest du für ein besseres Verständis auch mal die SQL Anweisungen von EF loggen lassen, damit dir auch klar wird, wie die Daten geladen werden.

Im einfachsten Fall sollte der Code zum laden dann ungefähr so aussehen.
Dafür musst du aber der Children Klasse eine MotherId Property geben, damit diese auch direkt verlinkt ist.
Die MotherChildren Klasse kannst du in dem Zuge auch komplett verwerfen, da do damit eben keine 1:n Beziehung sondern eine n:m Beziehung abbildest.
Hat dir Abt aber auch schon 2-3 mal geschrieben.

Die Collection in Mother würde ich dann auch von HashSet umstellen auf eine List, was auch sinnvoller für EF ist und dir auch erst einige Optionen wie Suchen und direkt Zugriffe erlaubt.


var result = context.TB_Mothers.Include(mother => mother.Childrens).Where(mother => mother.Childrens.Contains(children => children.ChildName == "Name")).ToList();

Nachtrag:
Abt war schneller 😦

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.807 Beiträge seit 2008
vor 3 Jahren

Die Collection in Mother würde ich dann auch von HashSet umstellen auf eine List, was auch sinnvoller für EF ist und dir auch erst einige Optionen wie Suchen und direkt Zugriffe erlaubt.

Es ist in der pauschalen Formulierung nicht "sinnvoller".
EFCore verwendet unter der Haube das HashSet; für Relationen wird empfohlen einfach ICollection für die Eigenschaften zu verwenden.

Der Grund ist, dass das HashSet für 99% der Zwecke die performantere und bessere Lösung für den Umgang mit Daten ist; vor allem da EFCore beim Schreiben viele Vergleichsoperationen ausführt.
Des weiteren die Implementierung in EF Core vom HashSet dazu, dass die Collection Property niemals null ist.

Da die Eigenschaften eben mit ICollection dekoriert werden, ändert das am Suchen und im Sinne der Direktzugriffe auch nichts.

  
var result = context.TB_Mothers.Include(mother => mother.Childrens).Where(mother => mother.Childrens.Contains(children => children.ChildName == "Name")).ToList();  
  

Je nach EFCore Version kann Contains zu einer Client Execution führen, was man vermeiden sollte.
Neuere EFCore Versionen werfen entsprechend eine Exception.

Die Variante von MrSparkle ist die hier zur Fragestellung bessere und passendere Lösung.

T
Taucher Themenstarter:in
307 Beiträge seit 2008
vor 3 Jahren

Ich danke euch allen für die Antworten! Ich werde mich morgen nochmal hinsetzen, und denke auch das es dann klappen wird, und ich dann auch hoffentlich sagen kann, wo meine Blockade lag...

@Abt

Sorry, was Du gemacht hast ist kein Reverse Engineering sondern blind im Dunkel stochern; sorry für die direkten Worte.
Das hat mit Reverse Engineering nichts, aber auch gar nichts zutun. Nicht mal Ansatzweise.

Hier stehts, und genau das habe ich gemacht.
Reverse Enginering

16.807 Beiträge seit 2008
vor 3 Jahren

Hier stehts, und genau das habe ich gemacht.

Ach Du sprichst von Entity Type Scaffolding... hat sich angehört als ob Du von Reverse Engineering als Fachbegriff sprichst.

Umso mehr stellt sich die Frage, was Du vor hast und mit was für einem Ziel Du arbeitest, wenn Dir ein Generator anhand einer 1:n Vorgabe wirklich n:m Zeug generiert haben soll.