EF Context Anwendungsweit verfügbar machen?

  • C#

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

    EF Context Anwendungsweit verfügbar machen?

    Hallo,

    nach längerem melde ich mich mit meinem Projekt noch einmal zurück.
    Ich habe in der Zwischenzeit die Oberfläche gebaut und mit einem Kollegen aus den USA einige Animationen erstellt.
    Der Context steht und ein Login zur lokalen DB funktioniert.
    Jetzt steh ich allerdings ein wenig auf dem Schlauch, wie ich nun die Daten aus der DB Anwendungsweit verfügbar habe...

    Der Ablauf wäre ja so: User loggt sich ein, Seine Daten aus der DB werden abgerufen und in der View angezeigt.

    Hier mal ein paar Codes:
    Der DB Context:
    [spoiler Name=DBContext]

    C#-Quellcode

    1. namespace MHoApps.Bazaar.DAL
    2. {
    3. /// <summary>
    4. /// die Klasse für die Verbindung zur Datenbank und das befüllen der Tabellen
    5. /// </summary>
    6. public class BazaarDbContext :DbContext
    7. {
    8. #region Private Properties
    9. private string conString = @"Server=(localdb)\MSSQLLocalDB;Database=BazaarDb;Trusted_Connection=True;";
    10. #endregion
    11. #region Constructor
    12. /// <summary>
    13. /// default constructor
    14. /// </summary>
    15. public BazaarDbContext()
    16. {}
    17. public BazaarDbContext(DbContextOptions<BazaarDbContext> options) : base(options)
    18. {}
    19. /// <summary>
    20. /// constructor mit übergabe des connection string
    21. /// </summary>
    22. /// <param name="connectionString"> der connection string zur Datenbank</param>
    23. public BazaarDbContext(string connectionString)
    24. {
    25. conString = connectionString;
    26. }
    27. #endregion
    28. #region DbSets
    29. /// <summary>
    30. /// Abbilden der Tabellen der Datenbank
    31. /// </summary>
    32. public virtual DbSet<Person> Persons { get; set; }
    33. public virtual DbSet<Article> Articles { get; set; }
    34. public virtual DbSet<BazaarEvent> BazaarEvents { get; set; }
    35. public virtual DbSet<LogInData> LogInData { get; set; }
    36. public virtual DbSet<Organization> Organizations { get; set; }
    37. public virtual DbSet<PersonBazaarEvent> PersonBazaarEvents { get; set; }
    38. #endregion
    39. #region Overrides
    40. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    41. {
    42. if(!optionsBuilder.IsConfigured)
    43. {
    44. optionsBuilder.UseSqlServer(conString).ConfigureWarnings(warnings => warnings.Throw(CoreEventId.IncludeIgnoredWarning));
    45. }
    46. }
    47. protected override void OnModelCreating(ModelBuilder modelBuilder)
    48. {
    49. modelBuilder.Entity<PersonBazaarEvent>().HasKey(k => new { k.BazaarEventId, k.PersonId });
    50. modelBuilder.Entity<PersonBazaarEvent>().HasOne(a => a.Person).WithMany(b => b.PersonBazaarEvents).HasForeignKey(c => c.PersonId);
    51. modelBuilder.Entity<PersonBazaarEvent>().HasOne(a => a.BazaarEvent).WithMany(b => b.Sellers).HasForeignKey(c => c.BazaarEventId);
    52. }
    53. #endregion
    54. }
    55. }

    [/spoiler]

    Das Handling für die DB
    [spoiler Name=DBHandling]

    C#-Quellcode

    1. namespace MHoApps.Bazaar.DAL
    2. {
    3. /// <summary>
    4. /// Klasse um die Datenbank mit DummyDaten zu befüllen
    5. /// </summary>
    6. public class BazaarDBHandling
    7. {
    8. #region Constructor
    9. public BazaarDBHandling()
    10. {
    11. }
    12. #endregion
    13. #region Initializer Methods
    14. public void Seed()
    15. {
    16. using (var _ctx = new BazaarDbContext())
    17. {
    18. _ctx.Database.EnsureCreated();
    19. if (!_ctx.Persons.Any())
    20. {
    21. // einen Verein anlegen
    22. var org = new Organization
    23. {
    24. Name = "Förderverein KiTa Kunterbunt e.V.",
    25. Street = "Freiherr-vom-Stein-Strasse 23",
    26. PostalCode = "56244",
    27. City = "Sessenhausen",
    28. License = LicenseTypeEnum.Pro
    29. };
    30. // den dazugehörigen Verantwortlichen anlegen
    31. var responsible = new Person
    32. {
    33. FirstName = "Michael",
    34. LastName = "Hoffmann",
    35. Email = "contact@mhoapps.de",
    36. PersonCategory = PersonCategoryEnum.Responsible,
    37. Organization = org,
    38. AccessData = new LogInData
    39. {
    40. UserName = "m.hoffmann",
    41. EncryptedPassword = GetMD5Hash("mh0ffm@nn"),
    42. Role = LogInDataRoleEnum.EventAdmin,
    43. IsInitialPassword = true,
    44. IsActive = true
    45. }
    46. };
    47. //ein paar Verkäufer mit Artikeln anlegen
    48. var sellers = new List<Person>
    49. {
    50. new Person
    51. {
    52. FirstName = "Helga",
    53. LastName = "Muster",
    54. Email = "claudia@muster.de",
    55. PersonCategory = PersonCategoryEnum.Seller,
    56. SellerNumber = 1,
    57. AccessData = new LogInData()
    58. {
    59. UserName = "cmuster",
    60. EncryptedPassword = GetMD5Hash("c.muster#2019"),
    61. IsInitialPassword = true,
    62. IsActive = true,
    63. Role = LogInDataRoleEnum.Seller
    64. },
    65. Articles = new List<Article>()
    66. {
    67. new Article()
    68. {
    69. ArticleNumber = 123,
    70. Description = "Spiel - Schnappt Hubi",
    71. Price = 2.5m,
    72. Quantity = 1,
    73. Sold = false
    74. }
    75. }
    76. },
    77. new Person
    78. {
    79. FirstName = "Klara",
    80. LastName = "Schmidt",
    81. Email = "klara@schmidt.de",
    82. PersonCategory = PersonCategoryEnum.Seller,
    83. SellerNumber = 2,
    84. AccessData = new LogInData()
    85. {
    86. UserName = "klara",
    87. EncryptedPassword = GetMD5Hash("schmidt"),
    88. IsInitialPassword = true,
    89. IsActive = true,
    90. Role = LogInDataRoleEnum.Seller
    91. },
    92. Articles = new List<Article>()
    93. {
    94. new Article()
    95. {
    96. ArticleNumber = 456,
    97. Description = "grüne Jacke",
    98. Price = 2.5m,
    99. Quantity = 1,
    100. Sold = false
    101. }
    102. }
    103. },
    104. new Person
    105. {
    106. FirstName = "Elvira",
    107. LastName = "Muster",
    108. Email = "elvira@muster.de",
    109. PersonCategory = PersonCategoryEnum.Seller,
    110. SellerNumber = 3,
    111. AccessData = new LogInData()
    112. {
    113. UserName = "elvira",
    114. EncryptedPassword = GetMD5Hash("elvira"),
    115. IsInitialPassword = true,
    116. IsActive = true,
    117. Role = LogInDataRoleEnum.Seller
    118. },
    119. Articles = new List<Article>()
    120. {
    121. new Article()
    122. {
    123. ArticleNumber = 311,
    124. Description = "Spiel - Schnappt Hubi",
    125. Price = 2.5m,
    126. Quantity = 1,
    127. Sold = false
    128. }
    129. }
    130. },
    131. new Person
    132. {
    133. FirstName = "Henriette",
    134. LastName = "Schmidt",
    135. Email = "henriette@schmidt.de",
    136. PersonCategory = PersonCategoryEnum.Seller,
    137. SellerNumber = 4,
    138. AccessData = new LogInData()
    139. {
    140. UserName = "henriette",
    141. EncryptedPassword = GetMD5Hash("henriette"),
    142. IsInitialPassword = true,
    143. IsActive = true,
    144. Role = LogInDataRoleEnum.Seller
    145. },
    146. Articles = new List<Article>()
    147. {
    148. new Article()
    149. {
    150. ArticleNumber = 456,
    151. Description = "grüne Jacke",
    152. Price = 2.5m,
    153. Quantity = 1,
    154. Sold = false
    155. }
    156. }
    157. },
    158. new Person
    159. {
    160. FirstName = "Margot",
    161. LastName = "Muster",
    162. Email = "margot@muster.de",
    163. PersonCategory = PersonCategoryEnum.Seller,
    164. SellerNumber = 5,
    165. AccessData = new LogInData()
    166. {
    167. UserName = "margot",
    168. EncryptedPassword = GetMD5Hash("margot"),
    169. IsInitialPassword = true,
    170. IsActive = true,
    171. Role = LogInDataRoleEnum.Seller
    172. },
    173. Articles = new List<Article>()
    174. {
    175. new Article()
    176. {
    177. ArticleNumber = 5123,
    178. Description = "Spiel - Schnappt Hubi",
    179. Price = 2.5m,
    180. Quantity = 1,
    181. Sold = false
    182. }
    183. }
    184. },
    185. new Person
    186. {
    187. FirstName = "Emma",
    188. LastName = "Schmidt",
    189. Email = "emma@schmidt.de",
    190. PersonCategory = PersonCategoryEnum.Seller,
    191. SellerNumber = 6,
    192. AccessData = new LogInData()
    193. {
    194. UserName = "emma",
    195. EncryptedPassword = GetMD5Hash("emma"),
    196. IsInitialPassword = true,
    197. IsActive = true,
    198. Role = LogInDataRoleEnum.Seller
    199. },
    200. Articles = new List<Article>()
    201. {
    202. new Article()
    203. {
    204. ArticleNumber = 6456,
    205. Description = "grüne Jacke",
    206. Price = 2.5m,
    207. Quantity = 1,
    208. Sold = false
    209. }
    210. }
    211. },
    212. };
    213. // Basare anlegen
    214. var aevent = new BazaarEvent
    215. {
    216. EventName = "Basar Event 1",
    217. EventDate = DateTime.Now.AddDays(14),
    218. EventToken = "E-0815-2019",
    219. ResponsiblePerson = responsible,
    220. Sellers = new List<PersonBazaarEvent>()
    221. };
    222. var bevent = new BazaarEvent
    223. {
    224. EventName = "Basar Event 2",
    225. EventDate = DateTime.Now.AddDays(30),
    226. EventToken = "E-0816-2019",
    227. ResponsiblePerson = responsible,
    228. Sellers = new List<PersonBazaarEvent>()
    229. };
    230. //die Verkäufer zu den Events hinzufügen
    231. aevent.Sellers.Add(new PersonBazaarEvent { BazaarEvent = aevent, Person = sellers[0] });
    232. aevent.Sellers.Add(new PersonBazaarEvent { BazaarEvent = aevent, Person = sellers[1] });
    233. aevent.Sellers.Add(new PersonBazaarEvent { BazaarEvent = aevent, Person = sellers[2] });
    234. bevent.Sellers.Add(new PersonBazaarEvent { BazaarEvent = bevent, Person = sellers[3] });
    235. bevent.Sellers.Add(new PersonBazaarEvent { BazaarEvent = bevent, Person = sellers[4] });
    236. bevent.Sellers.Add(new PersonBazaarEvent { BazaarEvent = bevent, Person = sellers[5] });
    237. //alles dem Context hinzufügen
    238. _ctx.Organizations.Add(org);
    239. _ctx.Persons.Add(responsible);
    240. _ctx.Persons.AddRange(sellers);
    241. _ctx.BazaarEvents.Add(aevent);
    242. _ctx.BazaarEvents.Add(bevent);
    243. //in die Datenbank speichern und Fehler zurückgeben falls es nicht geklappt hat
    244. if (_ctx.SaveChanges() < 1) throw new Exception("Unerwarteter Rückgabewert beim speichern...");
    245. }
    246. }
    247. }
    248. #endregion
    249. #region Data Retrieval Methods
    250. public void LoadResponsibleData(string user, string pass)
    251. {
    252. using (var _ctx = new BazaarDbContext())
    253. {
    254. //angemeldete Person im Context
    255. var person = _ctx.Persons
    256. .Include(org => org.Organization)
    257. .Include(ad => ad.AccessData)
    258. .Include(pbe => pbe.PersonBazaarEvents)
    259. .ThenInclude(ev => ev.BazaarEvent)
    260. .ThenInclude(resp => resp.ResponsiblePerson)
    261. .Include(art => art.Articles)
    262. .AsNoTracking()
    263. .Single(p => p.AccessData.UserName == user && p.AccessData.EncryptedPassword == GetMD5Hash(pass));
    264. //BazaarDaten für den Responsible laden
    265. var bazaarEvent = _ctx.BazaarEvents
    266. .Include(rp => rp.ResponsiblePerson) //includieren, damit Zugriff auf die Details besteht (LogIn Daten, Name usw.)
    267. .ThenInclude(org => org.Organization) //danach includieren um Zugriff auf die Organisation Daten zu erhalten
    268. .Include(pe => pe.Sellers) //Sellers ist vom Typ ICollection<PersonBazaarEvent>, muss includiert werden um an die Verkäufer ran zu kommen
    269. .ThenInclude(p => p.Person) //von den Verkäufern includieren um auf die Details Zugriff zu bekommen (Name, Verkäufernummer usw.)
    270. .ThenInclude(a => a.Articles) //wiederum von der Person der Sellers includieren um auf desen Artikel Details zu kommen (Artikelnr., Beschreibung usw.)
    271. .AsNoTracking()
    272. .Where(p => p.ResponsiblePerson == person).ToList();
    273. }
    274. }
    275. public bool CheckLogInData(string user, string pass)
    276. {
    277. using(var _ctx = new BazaarDbContext())
    278. {
    279. return _ctx.Persons.FirstOrDefault(p => p.AccessData.UserName == user && p.AccessData.EncryptedPassword == GetMD5Hash(pass) && p.AccessData.IsActive && !p.DeletedFlag) != null;
    280. }
    281. }
    282. #endregion
    283. #region HelperMethods
    284. private readonly Random rnd = new Random();
    285. internal string GetMD5Hash(string text)
    286. {
    287. if (string.IsNullOrEmpty(text)) return string.Empty;
    288. MD5 md5 = new MD5CryptoServiceProvider();
    289. byte[] Data = Encoding.ASCII.GetBytes(text);
    290. byte[] Result = md5.ComputeHash(Data);
    291. return BitConverter.ToString(Result);
    292. }
    293. internal string CreatePassword(int passwordLength, string AllChars = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz0123456789!@$?_-[](){}=§$%#&/")
    294. {
    295. return new string(Enumerable.Repeat(AllChars, passwordLength).Select(s => s[rnd.Next(s.Length)]).ToArray());
    296. }
    297. #endregion
    298. }
    299. }
    [/spoiler]

    Dann das LogIn View Model
    [spoiler Name=LoginViewModel]

    C#-Quellcode

    1. namespace MHoApps.Bazaar.ViewModel
    2. {
    3. /// <summary>
    4. /// das ViewModel für die Anmeldeseite
    5. /// </summary>
    6. public class LoginViewModel : BaseViewModel
    7. {
    8. private BazaarDBHandling _ctx = new BazaarDBHandling();
    9. #region Public Properties
    10. public string Email { get; set; }
    11. public bool LoginIsRunning { get; set; }
    12. #endregion
    13. #region Commands
    14. public ICommand LogInCommand { get; set; }
    15. public ICommand RegisterCommand { get; set; }
    16. #endregion
    17. #region Constructor
    18. /// <summary>
    19. /// default constructor
    20. /// </summary>
    21. public LoginViewModel()
    22. {
    23. LogInCommand = new RelayCommand(async (parameter) => await LoginAsync(parameter));
    24. RegisterCommand = new RelayCommand(async r => await RegisterAsync());
    25. }
    26. #endregion
    27. #region Command Methods
    28. /// <summary>
    29. /// den User einloggen
    30. /// </ summary>
    31. /// <param name = "parameter"> der <see cref = "SecureString" />, der aus der View für das Benutzerkennwort übergeben wurde </ param>
    32. /// <returns> </ returns>
    33. public async Task LoginAsync(object parameter)
    34. {
    35. await RunCommandAsync(() => LoginIsRunning, async () =>
    36. {
    37. var ctx = new BazaarDBHandling();
    38. var email = Email;
    39. var pass = (parameter as IHavePassword).SecurePassword.Unsecure();
    40. if (_ctx.CheckLogInData(email, pass))
    41. {
    42. _ctx.LoadResponsibleData(email, pass); //hier werden die Daten geladen die Anwendungsweit verfügbar sein sollen
    43. IoC.Get<ApplicationViewModel>().GoToPage(ApplicationPageEnum.Main, new MainViewModel());
    44. }
    45. else
    46. {
    47. await IoC.UI.ShowMessage(new MessageBoxDialogViewModel
    48. {
    49. Title = "Falsche Zugangsdaten",
    50. Message = "Ihre Zugangsdaten waren nicht korrekt, bitte versuchen Sie es erneut"
    51. });
    52. }
    53. });
    54. }
    55. /// <summary>
    56. /// zur Registrierungsseite wechseln
    57. /// </summary>
    58. /// <returns></returns>
    59. public async Task RegisterAsync()
    60. {
    61. IoC.Get<ApplicationViewModel>().GoToPage(ApplicationPageEnum.Register);
    62. await Task.Delay(1);
    63. }
    64. #endregion
    65. }
    66. }
    [/spoiler]

    im MainViewModel hab ich zur Zeit noch nichts drin stehen, hier müsste ich aber ja irgendwie die Daten haben um weitere Daten anzeigen zu können.

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

    Sowohl von MS als auch von jedem der sich mit EF beschäftigt wird dringenst empfohlen mit Using zu Arbeiten.
    Es gibt natürlich umstände da ist dies nicht möglich, und man muss sich eine Variable erstellen welche den Context hält, dann muss man aber zusehen das man im Dispose auch brav den Context disposed und das Dispose der Klasse auch aufruft.

    den Context lange offen zu halten ist eine sehr schlechte Idee. Nicht wegen dem Speicher oder so, sondern weil du in Teufels küche kommst. EF besitze einen 1st Level und einen Second Level Cache.
    Ich könnte nun lange ausschweifen warum und weshalb es schlecht ist den context offen zu halten, das mach ich aber eher erste wenn die nächsten Fragen aufkommen und du dich etwas mehr mit EF beschäftigt hast. Sonst denke ich verstehst du die Erklärungen nicht wirklich. Glaub mir, es ist nicht ratsam, da kommen die wirrsten Fehler und Fehlverhalten zu Tage. (Zumindest denkst du es ist ein Fehlverhalten, ist es aber nicht)

    Was macht, bzw. wofür ist "LoadResponsibleData" gut?

    Ein paar Dinge vorab.

    * Versuche immer wenn möglich mit Using zu arbeiten
    * Versuche wo möglich mit NoTracking() abzurufen, oder noch besser - schalte Tracking ab und schalte es nur nach bedarf zu mit AsTracking()
    * Verwende NIE LazyLoading


    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 Sascha,
    Danke Dir für die Erklärung.
    Using benutze ich meiner Meinung nach ja beim Context:

    C#-Quellcode

    1. public void LoadResponsibleData(string user, string pass)
    2. {
    3. using (var _ctx = new BazaarDbContext())
    4. {
    5. //angemeldete Person im Context
    6. var person = _ctx.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. .AsNoTracking()
    14. .Single(p => p.AccessData.UserName == user && p.AccessData.EncryptedPassword == GetMD5Hash(pass));
    15. //BazaarDaten für den Responsible laden
    16. var bazaarEvent = _ctx.BazaarEvents
    17. .Include(rp => rp.ResponsiblePerson) //includieren, damit Zugriff auf die Details besteht (LogIn Daten, Name usw.)
    18. .ThenInclude(org => org.Organization) //danach includieren um Zugriff auf die Organisation Daten zu erhalten
    19. .Include(pe => pe.Sellers) //Sellers ist vom Typ ICollection<PersonBazaarEvent>, muss includiert werden um an die Verkäufer ran zu kommen
    20. .ThenInclude(p => p.Person) //von den Verkäufern includieren um auf die Details Zugriff zu bekommen (Name, Verkäufernummer usw.)
    21. .ThenInclude(a => a.Articles) //wiederum von der Person der Sellers includieren um auf desen Artikel Details zu kommen (Artikelnr., Beschreibung usw.)
    22. .AsNoTracking()
    23. .Where(p => p.ResponsiblePerson == person).ToList();
    24. }
    25. }

    die LoadResponsibleData soll quasi die Daten des angemeldeten Users aus der DB holen, also seine eigenen Daten wie Name, Email, zugehöriger Verein usw. sowie alle Events dieses Responsible mit deren Verkäufern und Artikeln.

    AsNoTracking hab ich ja auch drin, die Methode haben wir glaub zusammen in einem anneren Thread verzapft
    "Hier könnte Ihre Werbung stehen..."

    MichaHo schrieb:

    Using benutze ich meiner Meinung nach ja beim Context

    Aber ich denke du fragst hier in diesem Thread ja Allgemein für später im ViewModel richtig.
    Zumindest suggeriert der Titel das du vorhast ohne Using zu arbeiten und den Context 1x aufmachen willst um damit zu Arbeiten. Habe ich das richtig verstanden?

    Zudem verwendest du im LoginViewModel kein Using. Hast aber auch kein IDisposable implementiert und Disposed somit den Context auch nicht.

    MichaHo schrieb:

    die LoadResponsibleData soll quasi die Daten des angemeldeten Users aus der DB holen

    Ja, das tut sie auch, aber weiter wird nichts damit gemacht. Die Daten können auch durch das Notracking nicht weiterverwendet werden da diese nicht im First Level Cache sind ausgrund des NoTracking().
    Die Methode ruft also Daten aus der DB, diese werden aber nirgens verwendet. Ist ja auch ne Void.
    OK, du rufst die Methode im LoginViewModel auf, aber was bringt das? Wo hast du die Daten dann zur Verfügung? Ich denke nirgens. Und spätestens nach einem Disposing des Context wäre es sowieso weg. Verstehst du in etwa was ich meine?

    MichaHo schrieb:

    AsNoTracking hab ich ja auch drin

    Ja, wollte nur nochmals aufzählen was ich für wichtig halte in Verbindung mit EF.

    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. ##

    OK, ich hab ja 2 Klassen im DAL, einmal die Klasse BazaarDBContext welches der eigentliche Context ist und einmal BazaarDBHandling wo ich über Using immer den Context abfrage (Seeding, LoginDaten prüfen, Daten laden)
    Ich will den Context nicht offen halten. Ich verstehe auch, das die Daten immer dann geladen werden sollen, wenn sie gebraucht werden.
    Ich müsste also entweder die Zugangsdaten irgendwo zwischenspeichern, oder? oder die Daten bei erfolgreichem einloggen laden und an ein anderes ViewModel weitergeben...

    Hier steh ich auf dem Schlauch. Das Einloggen klappt, er schaut in die DB, sucht die AcessDaten des Users und prüft ob die Daten stimmen oder nicht.
    Wenns stimmt navigiert er zum eigentlichen Hauptbildschirm. In diesem ist ein Seitenmenü wo die Events dieses Users angezeigtw erden sollen.
    Alle Views und Controls sind gebunden, mit DummyDaten funktioniert das auch:


    Ich versteh jetzt halt nicht, wie ich an die Daten komme in den einzelnen Views

    EDIT: warte, ich glaub ich bin auf einen Weg gestoßen.
    ich hab im EventListViewModel eine Liste mit AllEvents und weise dieser die Ctx.BazaarEvents.ToList() zu, dadurch werden die angeziegt....
    Ich probier mal weiter
    "Hier könnte Ihre Werbung stehen..."

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

    Hallo

    OK, schaun wir uns folgendes an:

    C#-Quellcode

    1. if (_ctx.CheckLogInData(email, pass))
    2. {
    3. _ctx.LoadResponsibleData(email, pass); //hier werden die Daten geladen die Anwendungsweit verfügbar sein sollen
    4. IoC.Get<ApplicationViewModel>().GoToPage(ApplicationPageEnum.Main, new MainViewModel());
    5. }
    6. else
    7. {
    8. await IoC.UI.ShowMessage(new MessageBoxDialogViewModel
    9. {
    10. Title = "Falsche Zugangsdaten",
    11. Message = "Ihre Zugangsdaten waren nicht korrekt, bitte versuchen Sie es erneut"
    12. });
    13. }


    Ja, es wird geprüft ob die Logindaten stimmen und dann wird Navigiert. Aber _ctx.LoadResponsibleData(email, pass); bringt dir nix. Du rufst die Daten ab, speicherst diese aber nicht. Innerhalb der Methode befüllst du zwei Variablen person und bazaarEvent , machst aber weiter nix damit.

    Es ist mir klar was du willst und verstädlich.
    Du willst speichern wer gerade Angemeldet ist um damit später immer im Programm weiter zu arbeiten.

    Da stellt sich die Frage ob du nun wirklich ALLE Informationen über den user speichern willst oder ob die ID des Users nicht reicht.
    Ich habe auch dazu tendiert die Userdaten und dessen Rechte/Rollen und Detaildaten irgendwo abzulegen um schnell immer zugriff daauf zu haben. Es hat sich aber gezeigt das dies nicht so gut ist, seither speichere ich nur das nötigste und alles andere rufe ich nach bedarf ab, muss man abwiegen. Aber zurück zur Sache.

    Ich bin bisher ganz gut mit einer Singleton Klasse gefahren. Bei dieser kann es eben nur eine Instanz de rKlasse geben. Dort gibt es dann einfach Variablen wekche die Daten halten wie z.b. CurrentLoggedInUser

    Um die Frage weiter zu beantworten brauche ich noch eine Info. Hast du den DataAccessLayer ausgelagert auf eine eigene Assembly (dll) oder ist die im selben Projekt).
    Wenn ich die Info habe gehts weiter mit meiner Antwort. ;)

    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, du hast mich genau richtig verstanden und auf die Idee, lediglich die ID irgendwo zwischen zu speichern bin ich garnet gekommen *facepalm*
    Ähm, ja, der DAL ist ein eigenes Projekt:


    Ich hab auch schon eine Singleton Klasse, nämlich das ApplicationViewModel, dort könnte ich das Zwischenspeichern

    EDIT:
    OK, die Login hab ich abgeändert und speichere nun die UserID des angemeldeten Users:

    C#-Quellcode

    1. public async Task LoginAsync(object parameter)
    2. {
    3. await RunCommandAsync(() => LoginIsRunning, async () =>
    4. {
    5. var ctx = new BazaarDBHandling();
    6. var email = Email;
    7. var pass = (parameter as IHavePassword).SecurePassword.Unsecure();
    8. if (_ctx.CheckLogInData(email, pass))
    9. {
    10. IoC.Get<ApplicationViewModel>().CurrentLoggedInUserID = _ctx.GetCurrentUserID(email, pass);
    11. IoC.Get<ApplicationViewModel>().GoToPage(ApplicationPageEnum.Main, new MainViewModel());
    12. }
    13. else
    14. {
    15. await IoC.UI.ShowMessage(new MessageBoxDialogViewModel
    16. {
    17. Title = "Falsche Zugangsdaten",
    18. Message = "Ihre Zugangsdaten waren nicht korrekt, bitte versuchen Sie es erneut"
    19. });
    20. }
    21. });
    22. }

    Das Application ViewModel:

    C#-Quellcode

    1. /// <summary>
    2. /// das View Model das die Application abbildet
    3. /// </summary>
    4. public class ApplicationViewModel : BaseViewModel
    5. {
    6. /// <summary>
    7. /// wahr wenn das Seitenmenü angezeigt werden soll
    8. /// </summary>
    9. public bool SideMenuVisible { get; set; } = false;
    10. /// <summary>
    11. /// wahr wenn das Settingsmenü gezeigt werden soll
    12. /// </summary>
    13. public bool SettingsMenuVisible { get; set; }
    14. public int CurrentLoggedInUserID { get; set; }
    15. /// <summary>
    16. /// navigiert zur angegbenen Seite
    17. /// </summary>
    18. /// <param name="page">die Seite zu der navigiert werden soll</param>
    19. /// <param name="vieModel">das ViewModel dazu, falls eins benötigt wird</param>
    20. public void GoToPage(ApplicationPageEnum page, BaseViewModel vieModel = null)
    21. {
    22. CurrentViewModel = vieModel;
    23. CurrentPage = page;
    24. OnPropertyChanged(nameof(CurrentPage));
    25. SideMenuVisible = page != ApplicationPageEnum.Login;
    26. }
    27. }

    und die Function GetCurrentUserID:

    C#-Quellcode

    1. public int GetCurrentUserID(string user, string pass)
    2. {
    3. using (var _ctx = new BazaarDbContext())
    4. {
    5. return _ctx.Persons.FirstOrDefault(p => p.AccessData.UserName == user && p.AccessData.EncryptedPassword == GetMD5Hash(pass) && p.AccessData.IsActive && !p.DeletedFlag).ID;
    6. }
    7. }



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

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

    OK, dann weiter

    Ich würde es so machen:

    C#-Quellcode

    1. public int CheckLogInData(string user, string pass)
    2. {
    3. using(var _ctx = new BazaarDbContext())
    4. {
    5. var usr = _ctx.Persons.FirstOrDefault(p => p.AccessData.UserName == user && p.AccessData.EncryptedPassword == GetMD5Hash(pass) && p.AccessData.IsActive && !p.DeletedFlag);
    6. //VB Code ;-)
    7. If usr is nothing then
    8. return 0
    9. else
    10. Return usr.ID
    11. End If
    12. }
    13. }


    Und dann;

    C#-Quellcode

    1. IoC.Get<ApplicationViewModel>().CurrentLoggedInUserID = _ctx.CheckLogInData(email, pass)
    2. if IoC.Get<ApplicationViewModel>().CurrentLoggedInUserID > 0)
    3. {
    4. IoC.Get<ApplicationViewModel>().GoToPage(ApplicationPageEnum.Main, new MainViewModel());
    5. }
    6. else
    7. {
    8. await IoC.UI.ShowMessage(new MessageBoxDialogViewModel
    9. {
    10. Title = "Falsche Zugangsdaten",
    11. Message = "Ihre Zugangsdaten waren nicht korrekt, bitte versuchen Sie es erneut"
    12. });
    13. }


    So sparst du dir schon mal einen Roundtrip zur DB.

    OK, weiter. So wie ich das sehe ich dein DAL ja der Context richtig? also so gesehen kein extra DataAccessLayer, sondern der EF Context ansich.
    Dann würde ich an deiner stelle das mit dem BazaarDbHandling sein lassen und einfach im ViewModel den Ef Context verwenden. so ist das anfangs am leichtesten nachzuvollziehen was an welcher Stelle passiert und wo welche Contextinstanz verwendet wird, das kann sonst wirklich sehr verwirrend sein.

    Ich hoffe du verstehst was ich meine. ansonst Frag bitte einfach 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. ##

    OK, hab ich verstanden. Ich hatte oben editiert und natürlich 2 mal die DB abgefragt.... Baue ich um.

    Den Context im ViewModel, OK, das muss ich dann in jedem ViewModel machen, wo ich Zugriff auf die Daten benötige, richtig?

    EDIT:
    @Nofear23m
    OK, irgendwo ist noch der Wurm drin, vermutlich im DB Context, ich bekomme nämlich keine Daten
    hier die Context Klasse:

    C#-Quellcode

    1. namespace MHoApps.Bazaar.DAL
    2. {
    3. /// <summary>
    4. /// die Klasse für die Verbindung zur Datenbank und das befüllen der Tabellen
    5. /// </summary>
    6. public class BazaarDbContext :DbContext
    7. {
    8. #region Private Properties
    9. private string conString = @"Server=(localdb)\MSSQLLocalDB;Database=BazaarDb;Trusted_Connection=True;";
    10. #endregion
    11. #region Constructor
    12. /// <summary>
    13. /// default constructor
    14. /// </summary>
    15. public BazaarDbContext()
    16. {}
    17. public BazaarDbContext(DbContextOptions<BazaarDbContext> options) : base(options)
    18. {}
    19. /// <summary>
    20. /// constructor mit übergabe des connection string
    21. /// </summary>
    22. /// <param name="connectionString"> der connection string zur Datenbank</param>
    23. public BazaarDbContext(string connectionString)
    24. {
    25. conString = connectionString;
    26. }
    27. #endregion
    28. #region DbSets
    29. /// <summary>
    30. /// Abbilden der Tabellen der Datenbank
    31. /// </summary>
    32. public virtual DbSet<Person> Persons { get; set; }
    33. public virtual DbSet<Article> Articles { get; set; }
    34. public virtual DbSet<BazaarEvent> BazaarEvents { get; set; }
    35. public virtual DbSet<LogInData> LogInData { get; set; }
    36. public virtual DbSet<Organization> Organizations { get; set; }
    37. public virtual DbSet<PersonBazaarEvent> PersonBazaarEvents { get; set; }
    38. #endregion
    39. #region Overrides
    40. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    41. {
    42. if(!optionsBuilder.IsConfigured)
    43. {
    44. optionsBuilder.UseSqlServer(conString).ConfigureWarnings(warnings => warnings.Throw(CoreEventId.IncludeIgnoredWarning));
    45. }
    46. }
    47. protected override void OnModelCreating(ModelBuilder modelBuilder)
    48. {
    49. modelBuilder.Entity<PersonBazaarEvent>().HasKey(k => new { k.BazaarEventId, k.PersonId });
    50. modelBuilder.Entity<PersonBazaarEvent>().HasOne(a => a.Person).WithMany(b => b.PersonBazaarEvents).HasForeignKey(c => c.PersonId);
    51. modelBuilder.Entity<PersonBazaarEvent>().HasOne(a => a.BazaarEvent).WithMany(b => b.Sellers).HasForeignKey(c => c.BazaarEventId);
    52. }
    53. #endregion
    54. }
    55. }


    die LoadData Methode habe ich abgeändert, wenn ich nen Haltepunkt setze ist _ctx.Persons leer (count = 0) es sind aber Daten in der DB drin.

    C#-Quellcode

    1. public void LoadResponsibleData(int id)
    2. {
    3. using (var _ctx = new BazaarDbContext())
    4. {
    5. //angemeldete Person im Context
    6. var person = _ctx.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. .AsNoTracking()
    14. .Single(p => p.ID == id);
    15. //BazaarDaten für den Responsible laden
    16. var bazaarEvent = _ctx.BazaarEvents
    17. .Include(rp => rp.ResponsiblePerson) //includieren, damit Zugriff auf die Details besteht (LogIn Daten, Name usw.)
    18. .ThenInclude(org => org.Organization) //danach includieren um Zugriff auf die Organisation Daten zu erhalten
    19. .Include(pe => pe.Sellers) //Sellers ist vom Typ ICollection<PersonBazaarEvent>, muss includiert werden um an die Verkäufer ran zu kommen
    20. .ThenInclude(p => p.Person) //von den Verkäufern includieren um auf die Details Zugriff zu bekommen (Name, Verkäufernummer usw.)
    21. .ThenInclude(a => a.Articles) //wiederum von der Person der Sellers includieren um auf desen Artikel Details zu kommen (Artikelnr., Beschreibung usw.)
    22. .AsNoTracking()
    23. .Where(p => p.ResponsiblePerson == person).ToList();
    24. }
    25. }


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

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

    MichaHo schrieb:

    wenn ich nen Haltepunkt setze ist _ctx.Persons leer (count = 0) es sind aber Daten in der DB drin

    Das ist normal. Wenn du genau dort einen Haltepunkt setzt ist es ja auch leer. die Daten sind in der DB. Aber der Context hat noch keine Abgerufen.
    Da du NoTracking() abrufst wird später in diesem Fall aber auch nix drinnen sein. Warum? Weil er die Daten nicht in den ChangeTracker läd. Eben NoTracking().
    Aber person sollte nicht null sein.

    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. ##

    OK, übersehen das ich meiner Liste nichts hinzugefügt habe
    Ich hab es jetzt mal nur im EventListViewModel gemacht:

    C#-Quellcode

    1. private void ReloadData(object obj)
    2. {
    3. using (var _ctx = new BazaarDbContext())
    4. {
    5. //angemeldete Person im Context
    6. var person = _ctx.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. .AsNoTracking()
    14. .Single(p => p.ID == IoC.Get<ApplicationViewModel>().CurrentLoggedInUserID);
    15. //BazaarDaten für den Responsible laden
    16. AllEvents = _ctx.BazaarEvents
    17. .Include(rp => rp.ResponsiblePerson) //includieren, damit Zugriff auf die Details besteht (LogIn Daten, Name usw.)
    18. .ThenInclude(org => org.Organization) //danach includieren um Zugriff auf die Organisation Daten zu erhalten
    19. .Include(pe => pe.Sellers) //Sellers ist vom Typ ICollection<PersonBazaarEvent>, muss includiert werden um an die Verkäufer ran zu kommen
    20. .ThenInclude(p => p.Person) //von den Verkäufern includieren um auf die Details Zugriff zu bekommen (Name, Verkäufernummer usw.)
    21. .ThenInclude(a => a.Articles) //wiederum von der Person der Sellers includieren um auf desen Artikel Details zu kommen (Artikelnr., Beschreibung usw.)
    22. .AsNoTracking()
    23. .Where(p => p.ResponsiblePerson == person).ToList();
    24. }
    25. }

    Somit werden alle Events dieses Users angezeigt.
    "Hier könnte Ihre Werbung stehen..."
    Sehr gut, da klappt das mal. Es werden sicher noch mehr Fragen bez. EF auftauchen.

    In diesem Fall ging es im Grunde ja nur um EF. Ich verschieben den Thread also mal nach sonstige Problemstellungen.

    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. ##

    Kein Problem. Und es wird definitiv Klemmen. EF muss man verstehen lernen. Es ist sehr angenehm zu Arbeiten, bietet aber dennoch so einige Fallstricke wenn man nicht weis wie funzt.

    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. ##