Code optimierung - EagerLoading EF Core

  • C#

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

    Code optimierung - EagerLoading EF Core

    Hallo,
    basierend auf diesem Thread habe ich nun die erste Methode zum Laden von Daten aus der DB erstellt und wollte nachfragen, ob dies die richtige Vorgehensweise ist oder ob es sinnvoller/eleganter/einfacher geht.

    Vorab hier die Seed Methode (speichern der Daten in die DB):
    Seeding

    C#-Quellcode

    1. public void Seed()
    2. {
    3. using (var context = new BazaarManagementDbContext())
    4. {
    5. if (!context.Organizations.Any())
    6. {
    7. List<Person> testPersons = new List<Person>();
    8. testPersons.Add(new Person()
    9. {
    10. FirstName = "Organisation",
    11. LastName = "Admin",
    12. Email = "admin@organisation.de",
    13. PersonCategory = PersonCategoryEnum.OrganizationAdmin,
    14. AccessData = new LogInData()
    15. {
    16. UserName = "admin",
    17. EncryptedPassword = GetMD5Hash("admin#2019"),
    18. IsInitialPassword = true,
    19. IsActive = true,
    20. Role = LogInDataRoleEnum.OrganisationAdmin
    21. }
    22. });
    23. testPersons.Add(new Person()
    24. {
    25. FirstName = "Verantwortlicher",
    26. LastName = "Basar",
    27. Email = "verantwortlicher@basar.de",
    28. PersonCategory = PersonCategoryEnum.EventResponsible,
    29. AccessData = new LogInData()
    30. {
    31. UserName = "responsible",
    32. EncryptedPassword = GetMD5Hash("res.ponsible#2019"),
    33. IsInitialPassword = true,
    34. Role = LogInDataRoleEnum.EventAdmin,
    35. IsActive = true
    36. }
    37. });
    38. testPersons.Add(new Person()
    39. {
    40. FirstName = "Helga",
    41. LastName = "Muster",
    42. Email = "claudia@muster.de",
    43. PersonCategory = PersonCategoryEnum.EventSeller,
    44. SellerNumber = 1,
    45. AccessData = new LogInData()
    46. {
    47. UserName = "cmuster",
    48. EncryptedPassword = "c.muster#2019",
    49. IsInitialPassword = true,
    50. IsActive = true,
    51. Role = LogInDataRoleEnum.Seller
    52. },
    53. Articles = new List<Article>()
    54. {
    55. new Article()
    56. {
    57. ArticleNumber = 123,
    58. Description = "Spiel - Schnappt Hubi",
    59. Price = 2.5m,
    60. Quantity = 1,
    61. Sold = false
    62. }
    63. }
    64. });
    65. context.Persons.AddRange(testPersons);
    66. Organization newOrg = new Organization()
    67. {
    68. Name = "KiTa Kunterbunt e.V.",
    69. License = LicenseTypeEnum.Light,
    70. OrganizationPersons = new List<Person>()
    71. };
    72. BazaarEvent firstEvent = new BazaarEvent()
    73. {
    74. EventName = "Kleider Basar Musterhausen",
    75. EventDate = DateTime.Now.AddDays(14),
    76. Provision = 20,
    77. MinProvision = 5m,
    78. Sellers = new List<PersonBazaarEvent>()
    79. };
    80. firstEvent.Sellers.Add(new PersonBazaarEvent() { BazaarEvent = firstEvent, Person = context.Persons.Local.Last() });
    81. firstEvent.Organization = newOrg;
    82. firstEvent.ResponsiblePerson = context.Persons.Local.ToList()[1];
    83. firstEvent.MaxSellerNumber = (int)newOrg.License;
    84. context.BazaarEvents.Add(firstEvent);
    85. newOrg.OrganizationPersons.Add(context.Persons.Local.ToList()[0]);
    86. newOrg.OrganizationPersons.Add(context.Persons.Local.ToList()[1]);
    87. newOrg.OrganizationPersons.Add(context.Persons.Local.ToList()[2]);
    88. context.Organizations.Add(newOrg);
    89. if (context.SaveChanges() < 1) throw new Exception("Unerwarteter Rückgabewert beim spiechern...");
    90. }
    91. }
    92. }



    und so hole ich die Daten einer bestimmten Person anhand der LogInDaten wieder aus der DB:
    Loading

    C#-Quellcode

    1. public void LoadingData(string user, string pass)
    2. {
    3. //BazaarEvents abrufen und zugehörige Daten laden (Organisation,Verantwortlicher, Verkäufer und deren Artikel)
    4. using (var context = new BazaarManagementDbContext())
    5. {
    6. var bazaarEvent = context.BazaarEvents
    7. .Include(o => o.Organization) //includieren, damit Zugriff auf die Organization Details besteht (Name usw.)
    8. .Include(rp => rp.ResponsiblePerson) //includieren, damit Zugriff auf die Details besteht (LogIn Daten, Name usw.)
    9. .Include(pe => pe.Sellers) //Sellers ist vom Typ ICollection<PersonBazaarEvent>, muss includiert werden um an die Verkäufer ran zu kommen
    10. .ThenInclude(p => p.Person) //von den Verkäufern includieren um auf die Details Zugriff zu bekommen (Name, Verkäufernummer usw.)
    11. .ThenInclude(a => a.Articles) //wiederum von der Person der Sellers includieren um auf desen Artikel Details zu kommen (Artikelnr., Beschreibung usw.)
    12. .Single(p => p.ResponsiblePerson.AccessData.UserName == user && p.ResponsiblePerson.AccessData.EncryptedPassword.Equals(GetMD5Hash(pass))); //hier nur die Daten zurückgeben, deren Logindaten es sind.
    13. System.Console.WriteLine($"Organisation: {bazaarEvent.Organization.Name}");
    14. System.Console.WriteLine($"Name: {bazaarEvent.ResponsiblePerson.FirstName} {bazaarEvent.ResponsiblePerson.LastName}");
    15. System.Console.WriteLine($"Event: {bazaarEvent.EventName}");
    16. foreach (var item in bazaarEvent.Sellers)
    17. {
    18. System.Console.WriteLine($"VerkäuferNr. {item.Person.SellerNumber}");
    19. System.Console.WriteLine($"Name: {item.Person.FirstName} {item.Person.LastName}");
    20. System.Console.WriteLine($"Anzahl Artikel: {item.Person.Articles.Count}");
    21. foreach (var art in item.Person.Articles)
    22. {
    23. System.Console.WriteLine($"Artikelnr. {art.ArticleNumber}");
    24. System.Console.WriteLine($"Artikel: {art.Description}");
    25. System.Console.WriteLine($"Preis: {art.Price.ToString("0.00")}");
    26. }
    27. }
    28. };
    29. }



    Im Grunde müsste es etwas veralgemeinert werden, denn es gibt 4 Arten von Personen
    1. Organisations Verwalter = PersonCategoryEnum.OrganizationAdmin
    2. Event Verantwortlicher = PersonCategoryEnum.EventResponsible
    3. Verkäufer = PersonCategoryEnum.EventSeller
    4. Event Verantwortlicher der gleichzeitig auch Verkäufer sein kann = PersonCategoryEnum.EventResponsibleSeller

    Je nachdem, wer sich anmeldet, müssen unterschiedle Daten geladen werden.
    Hier hab ich noch keine Idee wie ich das hin bekomme.

    Danke Euch
    "Hier könnte Ihre Werbung stehen..."
    Hallo

    Einen kleinen Fehler sehe ich hier. Du rufst die Daten mit Single ab.

    Da wird es krachen sobald der User bei mehr als einem Event als Verantwortlicher eingetragen ist, denn spätestens dann gibt es 2 Ergebnisse und es knallt da Single immer nur einen Datensatz sucht.
    EF macht hier in der SQL Abfrage ein "TOP (2)" und prüft ob zwei Datensätze zurückkommen. Ist dies der Fall bekommst du eine Exception.
    Aber auch wenn der User keinem Event als Verantwortlicher zugeodnet ist knallt es. Da gebe es noch SingleOrDefault() was null zurückgeben würde wenn es kein Event gibt.

    Hier wäre also ToList() oder FirstOrDefault() besser.

    Ich habe mal ein kleines Beispiel erstellt. Auch weil ich dann gleich ein wenig C# lernen kann:

    C#-Quellcode

    1. static void LoadingData(string user, string pass)
    2. {
    3. //BazaarEvents abrufen und zugehörige Daten laden (Organisation,Verantwortlicher, Verkäufer und deren Artikel)
    4. using (var context = new BazaarManagementDbContext(@"Server=(localdb)\MSSQLLocalDB;Database=BazaarDb;Trusted_Connection=True;"))
    5. {
    6. IQueryable<BazaarEvent> bazaarEvents = context.BazaarEvents //Ein Queryable mit der ersten Filterung erstellen
    7. .Where(p => p.ResponsiblePerson.AccessData.UserName == user && p.ResponsiblePerson.AccessData.EncryptedPassword.Equals(context.GetMD5Hash(pass))); //hier nur die Daten zurückgeben, deren Logindaten es sind.
    8. bazaarEvents = bazaarEvents.Where(p => p.DeletedFlag == false); // Weiteren Filter setzen
    9. bazaarEvents = bazaarEvents.Where(p => p.ResponsiblePerson.AccessData.UserName.ToLower() == user.ToLower()); // Und noch einen
    10. bazaarEvents = bazaarEvents.Include(i => i.Sellers); // Include setzen
    11. bazaarEvents = bazaarEvents.Skip(0).Take(10); //Nur die ersten 10 Datensätze
    12. List<BazaarEvent> foundedEvents = bazaarEvents.AsTracking().ToList(); // !!!! erst hier wird von der DB abgerufen !!!!!!
    13. // Die IDs von den Personen aufnehmen
    14. List<int?> personIdsForLoad = new List<int?>();
    15. personIdsForLoad.AddRange(foundedEvents.Where(x => x.ResponsiblePersonID.HasValue).Select(s => s.ResponsiblePersonID).ToList());
    16. // Die aufgenommenen Personen per PreLoading und RelationshipFixup nachladen
    17. // EF kümmert sich um das Verknüpfen der Nachgeladenen Personen mit den Events im Hintergrund
    18. context.Persons.Where(x => personIdsForLoad.Contains(x.ID)).ToList();
    19. };
    20. }



    Ich habe dir zu dem Code noch zwei Bilder hochgeladen.

    Wichtig ist zu verstehen das keine Abfrage zur DB geht solange du kein ToList(), SingleOrDefault() oder änliches auf dem IQueryable aufrufst.
    Ein Aufruf findet alerdings auch statt sobald du z.b. mit einer ForEach über das IQueryable drüberfährst. Also achtung.

    Du kannst auch mit mehreren If Bedingungen oder Select Case (Switch) Diverse Dinge steuern und nur in gewissen Fällen dann gewisse Includes machen oder Filter setzen.
    So kannst du dir die Abfrage zusamenbauen wie du willst. Erst wenn du fertig bist dann z.b. mit ToList() die abfrage starten.

    Hoffe das war verständlich.

    Grüße
    Sascha

    PS: Werde den Thread verschieben, da EF ja mit WPF nix zu tun hat.
    Bilder
    • 1.PNG

      35,17 kB, 588×493, 178 mal angesehen
    • 2.PNG

      38,04 kB, 629×506, 173 mal angesehen
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hi,
    Danke Dir, muss ich mir genauer anschauen.
    Ich hab nun den ganzen Nachmittag damit verbracht, die Daten spezifisch zu laden, je nachdem, wer sich anmeldet.
    Das sieht auch gut aus soweit => zumindest vom Ergebnis
    Datenladen

    C#-Quellcode

    1. public void LoadPersonData(string user, string pass)
    2. {
    3. using (var context = new BazaarManagementDbContext())
    4. {
    5. //angemeldete Person im Context
    6. var person = context.Persons
    7. .Include(org => org.Organization)
    8. .Include(ad => ad.AccessData)
    9. .Include(pbe => pbe.PersonBazaarEvents)
    10. .ThenInclude(ev => ev.BazaarEvent)
    11. .ThenInclude(resp => resp.ResponsiblePerson)
    12. .Include(art => art.Articles)
    13. .Single(p => p.AccessData.UserName == user && p.AccessData.EncryptedPassword == GetMD5Hash(pass));
    14. //BazaarDaten für den Responsible laden
    15. var bazaarEvent = context.BazaarEvents
    16. .Include(o => o.Organization) //includieren, damit Zugriff auf die Organization Details besteht (Name usw.)
    17. .Include(rp => rp.ResponsiblePerson) //includieren, damit Zugriff auf die Details besteht (LogIn Daten, Name usw.)
    18. .Include(pe => pe.Sellers) //Sellers ist vom Typ ICollection<PersonBazaarEvent>, muss includiert werden um an die Verkäufer ran zu kommen
    19. .ThenInclude(p => p.Person) //von den Verkäufern includieren um auf die Details Zugriff zu bekommen (Name, Verkäufernummer usw.)
    20. .ThenInclude(a => a.Articles) //wiederum von der Person der Sellers includieren um auf desen Artikel Details zu kommen (Artikelnr., Beschreibung usw.)
    21. .Where(p => p.ResponsiblePerson == person).ToList();
    22. //Alle Daten der Organisation für den Admin laden
    23. var organization = context.Organizations
    24. .Include(op => op.OrganizationPersons)
    25. .ThenInclude(pbe => pbe.PersonBazaarEvents)
    26. .ThenInclude(ev => ev.BazaarEvent)
    27. .ThenInclude(sel => sel.Sellers)
    28. .ThenInclude(p=> p.Person)
    29. .ThenInclude(art => art.Articles)
    30. .Single(oa => oa.ID == person.OrganizationId);
    31. Console.WriteLine("Für alle Personen gültige Daten");
    32. Console.WriteLine("");
    33. Console.WriteLine($"Organisation: {person.Organization.Name}");
    34. Console.WriteLine($"Name: {person.FirstName} {person.LastName}");
    35. Console.WriteLine($"Email: {person.Email}");
    36. Console.WriteLine($"PersonCategory: {person.PersonCategory.ToString()}");
    37. Console.WriteLine($"Benutzer Rolle: {person.AccessData.Role.ToString()}");
    38. Console.WriteLine("***********************************************************");
    39. Console.WriteLine("");
    40. switch (person.AccessData.Role)
    41. {
    42. case LogInDataRoleEnum.Anonym:
    43. //nix tun, kein Zugriff!!
    44. Console.WriteLine("Kein Zugriff!!");
    45. break;
    46. case LogInDataRoleEnum.Seller:
    47. //nur eigene Verkäuferdaten laden inklusive Artikel
    48. Console.WriteLine($"VerkäuferNr.: {person.SellerNumber}");
    49. foreach (var ev in person.PersonBazaarEvents)
    50. {
    51. Console.WriteLine($"Event: {ev.BazaarEvent.EventName} - am: {ev.BazaarEvent.EventDate}");
    52. Console.WriteLine($"Verantwortlicher: {ev.BazaarEvent.ResponsiblePerson.FirstName} {ev.BazaarEvent.ResponsiblePerson.LastName}");
    53. }
    54. foreach (var art in person.Articles)
    55. {
    56. System.Console.WriteLine($"Artikelnr. {art.ArticleNumber}");
    57. System.Console.WriteLine($"Artikel: {art.Description}");
    58. System.Console.WriteLine($"Preis: {art.Price.ToString("0.00")}");
    59. }
    60. break;
    61. case LogInDataRoleEnum.EventAdmin:
    62. //nur eigene Eventdaten laden samt Verkäufer und deren Artikel
    63. foreach (var ev in bazaarEvent)
    64. {
    65. foreach (var sel in ev.Sellers)
    66. {
    67. Console.WriteLine($"VerkäuferNr.: {sel.Person.SellerNumber}");
    68. Console.WriteLine($"Verkäufername: {sel.Person.FirstName} {sel.Person.LastName}");
    69. Console.WriteLine($"Event: {sel.BazaarEvent.EventName} - am: {sel.BazaarEvent.EventDate}");
    70. foreach (var art in sel.Person.Articles)
    71. {
    72. System.Console.WriteLine($"Artikelnr. {art.ArticleNumber}");
    73. System.Console.WriteLine($"Artikel: {art.Description}");
    74. System.Console.WriteLine($"Preis: {art.Price.ToString("0.00")}");
    75. }
    76. }
    77. Console.WriteLine("---");
    78. }
    79. break;
    80. case LogInDataRoleEnum.OrganisationAdmin:
    81. //alle daten der zugehörigen Organisation laden
    82. Console.WriteLine($"Anzahl Organisations Personen: {organization.OrganizationPersons.Count}");
    83. Console.WriteLine("");
    84. foreach (var pers in organization.OrganizationPersons)
    85. {
    86. Console.WriteLine($"Name: {pers.FirstName} {pers.LastName}");
    87. Console.WriteLine($"Email: {pers.Email}");
    88. //Console.WriteLine($"Benutzer Rolle: {pers.AccessData.Role}");
    89. foreach (var pbe in pers.PersonBazaarEvents)
    90. {
    91. foreach (var sel in pbe.BazaarEvent.Sellers)
    92. {
    93. Console.WriteLine($"Event: {sel.BazaarEvent.EventName} - am: {sel.BazaarEvent.EventDate}");
    94. Console.WriteLine($"Event Verantwortlicher: {sel.BazaarEvent.ResponsiblePerson.FirstName} {sel.BazaarEvent.ResponsiblePerson.LastName}");
    95. Console.WriteLine("");
    96. Console.WriteLine($"VerkäuferNr.: {sel.Person.SellerNumber}");
    97. Console.WriteLine($"Verkäufername: {sel.Person.FirstName} {sel.Person.LastName}");
    98. foreach (var art in sel.Person.Articles)
    99. {
    100. Console.WriteLine($"Artikelnr. {art.ArticleNumber}");
    101. Console.WriteLine($"Artikel: {art.Description}");
    102. Console.WriteLine($"Preis: {art.Price.ToString("0.00")}");
    103. }
    104. Console.WriteLine("");
    105. }
    106. }
    107. }
    108. break;
    109. }
    110. };
    111. }



    ich schau mir dennoch deine Lademethode an und gucke, ob ich meine dann dahingehend ändern kann.

    hier noch 2 Screenshots:
    Verantwortlicher und seine Events:
    Verkäufer und seine Artikel:
    "Hier könnte Ihre Werbung stehen..."
    Hallo

    Sieht soweit ganz gut aus. Mal abgesehen davon das du nirgens IsDeleted = False als Filter hinzufügst.

    Solange du keine Daten änderst (du keinen changetracker benötigst) empfehler ich ausserdem noch im NoTracking() abzurufen.
    Das beschleunigt das abrufen nochmals enorm.

    Gehe ich richtig der Annahme das dies jetzt nur zum Testen ist oder?
    Warum frag ich so doof....

    Du benötigst ja sicher nicht in diesem Moment wo der User sich anmeldet alle Daten im Ram oder?
    Das kann Fatal sein und mitunter auch vom Abruf her sehr lange dauern. Stell dir vor da sind mal zig hunderte Datensätze vorhanden.

    Man sollte immer ur die Daten abruffen die man im Moment benötigt. nicht mehr, nicht weniger.
    Beim Login hätte ich als erstes mal eine Funktion CheckLoginData(string username,string password) welche mir einen bool Wert zurückgibt.
    Wenn dies korrekt ist, also true zurückgibt rufe ich die Userdaten welche ich benötige ab. Denn ich muss ja nicht immer die Userdaten abrufen wenn der User auf Login klickt.
    Gibt er 10 mal ein falsches Passwort ein rufe ich vieleicht 10 mal die Userdaten von der DB ab. Ziel ist es die DB die Arbeit machen zu lassen, die kann das gut und nur lediglich ein 0 oder 1 von der DB zurück zu bekommen indem ich mit EF mit .Any() abrufe.

    So habe ich nur minimale Datenübertragung zwischen App und DB.

    Aber ich denke du verstehst das Prinzip ganz gut, dein code sieht ja gut aus. Jetzt kannst du dann die ersten ViewModels aufsetzen.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hi,
    Danke Dir.
    Ja, das war/ist zum testen, wie ich später an die Daten ran komme, die ich benötige.
    Ich habe viel rum experimentiert heute, die obige Lösung war die, die am besten für mich funktioniert hat.
    ich schaue mir morgen aber mal deine Geschichte an und gucke, wie ich das umsetzen kann.
    Bevor ich mit den VieModels anfange, möchte ich noch ein paar test Methoden basteln und schauen, was ich wie zurück bekomme.
    Das Daten anlegen hab ich ja noch garnicht behandelt, hier muss ich im Moemnt noch das Seeding erweitern und die DB neu erstellen lassen.
    Das möchte ich vorher noch ändern, bevor ich zu den ViewModels übergehe.
    "Hier könnte Ihre Werbung stehen..."
    Ja, nur zu. Es ist eh gut wenn man mal ein wenig damit rumspielt. So weis man später eher wo was passieren soll.
    Wobei du später auf jeden Fall noch so einige Überraschungen erleben wirst.

    Beispielsweise arbeitest du nun im Moment immer innerhalb des selben Using Blocks. Also immer mit der selben Context-Instanz. Das ändert sich später in der realen Verwendung schnell mal weil du gewisse Dinge ja auch über mehrere Methode hinaus laufen hast. z.b. Datenabruf im Konstruktor und das zurückschreiben in einem Command.

    Aber das kommt dann eh alles nach und nach.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Nofear23m schrieb:

    Also immer mit der selben Context-Instanz

    dazu hab ich noch ne Frage.
    Du hattest ja in deiner Seed Methode einen neuen context erstellt und im Consolen Programm auch.
    ist das richtig?
    "Hier könnte Ihre Werbung stehen..."
    Richtig. wäre anders ja auch gar nicht möglich. Warum?
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Bei EF gilt. Die Instanz sobald man sie nicht mehr benötigt wieder freigeben. Deshalb am besten im Using Block.
    du kannst dir viele Probleme einhandeln wenn dies nicht gemacht wird. Hatte da schon lustige Nebeneffekte.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    ja, das ist mir bewusst. ich meinte folgendes.
    Sagen wir es gibt eine Klasse Auto, die hat ne Methode fahren.
    Jetzt steht in der Methode fahren:

    C#-Quellcode

    1. void Fahren()
    2. {
    3. using(var auto = new Auto())
    4. {
    5. auto.Brems();
    6. };
    7. }


    und in dem Startprogramm (Console z.Bsp.)

    C#-Quellcode

    1. void Laden()
    2. {
    3. using(var auto = new Auto())
    4. {
    5. auto.Fahren();
    6. }
    7. }


    dann hab ich doch mit einer Methode = 2 Autos erstellt.

    Edit:
    noch eine Frage zum Laden von Daten. Du schreibst, das ich nicht auf IsDeleted prüfe.
    Kann ich da nicht im OnModelCreating direkt einen Filter setzen? oder macht das keinen Sinn?

    ich könnte ja dann im OnModelCreating:

    C#-Quellcode

    1. modelBuilder.Entity<Organization>().HasQueryFilter(o => !o.DeletedFlag);


    für jede Entity setzen, oder?

    "Hier könnte Ihre Werbung stehen..."

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „MichaHo“ ()

    Das ist richtig.

    Was in einem Fall der Klasse Auto nicht so gut ist. Denn du bekommst zwei verschiedene Instanzen von Auto.

    Im Falle das Entity Framework DB Context ist es erstmal egal. auch wenn du 5 Instanzen hast, alle haben den selben Connectionstring, gehen also alle auf die selbe DB. Somit egal.
    Der unterschied ist einfach, ich habe immer einen "frischen" ChangeTracker und einen "frischen" Cache.

    Beispiel:

    Ich habe zwei verschiedene Instanzen eines Context. Nennen wir die mal ctx1 und ctx2.

    In ctx1 rufe ich eine Person ab, da ich von dieser Person aber nur den UserNamen und die ID benötige rufe ich mittels Select nur diese zwei Spalten ab.

    Gut, an einer anderen stelle benötige ich nun abermals die Userdaten, diesmal aber alle Userdaten. Da ich die ID ja habe rufe ich mittels Find() ab.
    Ups, warum bekomme ich nicht die Daten wie Vor oder Nachname? alles null ?
    Weil Find() den cache nutzt und da es das Person-Objekt mit der ID im Cache bereits gibt wird die DB erst garnicht bemüht. Ist ja schon da. Tja, aber nicht komplett.

    Mache ich Find() aber mit ctx2 ist die Person mit der ID nicht im Cache dieser Instanz enthalten und die DB wird bemüht. Diesmal natürlich auch alle Spalten.

    Wie gesagt, nur ein kleines Beispiel wo man sich dann dämlich suchen könnte.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Das gilt aber nur für gewisse Methoden wie Find()

    ToList(), First() oder Single() ruft immer von der DB ab.

    Es gibt aber ja auch noch den ChangeTracker der auch nur für diese Instanz gilt. ;)
    EF füllt ganze Bücher, ich habe 3 daheim. Mein vorschlag. Einfach Anfangen und bei Fragen hier Fragen. Ich würde mal das erste ViewModel machen.
    Ich denke das wird bie dir der Login oder sowas sein. und dann mal die ersten Abfragen tätigen. Diese können wir dann gemeinsam vieleicht optimieren.

    Interessant wirds dann wenn du die ersten änderungen welche der User getätigt hat zurückschreiben willst.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##