[Homework] Database Apps - EF Code First
Колеги, ето го домашното по Code First. Има малък проблем с първата задача по конзолния клиент. Не иска да вземе домашните на студентите и съответно не ги отпечатва. Не можах да си намеря сам грешката и се надявам на помощ от ваша страна!
Условието отново има малък пропуск и ако се спазва стриктно таблицата Materials остава висяща в базата. Затова добавих малко условие в Additional requirements: • Materials can belong to one or more courses
Направих валидация на някои дати, за да не може да се подават дати в бъдещето. Това стана чрез имплементиране на собствен атрибут.
Иначе има няколко неща, с които се преборих.
1. Connection стринговете към базата - трябваше да ги добавям ръчно към App.config файловете на всичките проекти. Затова ви обръщам внимание, когато проверявате чужди домашни, не бързайте да пишете, че домашното не работи, а проверете дали случайно нямате такава инстанция на SQL Server при вас и затова не иска да тръгне.
2. Много време ми отне да накарам Seed методът да се извиква въобще. Просто се наложи да създам клас наследник на DropCreateDatabaseIfModelChanges класа, в който да овъррайдна Seed метода
3. Доста време ми отне да мине първоначалния seed, защото имаше проблеми с подредбата на данните, констрейнтите по foreign keys и т.н.
4. При анотациите за валидиране се оказа, че подаването само не errorMessage не е достатъчно, защото като гръмне EF въобще не го изписва никъде. Затова си подавайте и ErrorMessageResourceName. На мен това ми изяде 3 часа, докато разбера коя валидация ми пищи.
Моля, не копирайте домашното дословно в системата и не го качвайте като собствено!
И според мен е "по-правилно" да се вика в main-а на конзолния клиент. Ако го сетнеш в DbContext конструктора, други клиенти (web, desktop) ще са длъжни да ползват същия migration. Пак според нуждите
В моделите няма нужда да добавяш connection string-a.
Database.SetInitializer() го слагаш там където ти е началната точка на Application-a. Примерно в ASP.NET MVC проект го слагаш в Global.asax в Application_Start. В конзолен проект в Main методa.
@VGeorgiev
Оо да това е copy-paste грешка. Понеже ми гърмеше и аз навсякаде копирах "App.config" файловете.
Колкото до това да сложим "Database.SetInitializer()" в конструктора на контекста - Това си е чист "StackOverflow Exception".
Доколкото и аз търсих за мястото на SetInitializer, разбрах че няма правилно място. Важно е просто да се извика веднъж в началото от някъде.
За stackOverflowException-a се оказа, че изскача само при определени миграционни стратегии, не при всички. Затова може би Владо казва, че трябва да се пробва там.
Домашното ти ме подсети, че не съм си направил незадължителните пропъртита Nullable.
Ааа да и като стана дума за ""Nullable".
Кой е правилният начин :
1. public DateTime? BirthDay { get; set; }
ИЛИ
2. public Nullable<DateTime> BirthDay { get; set; }
Само синтактично се различават. Компилират се до едно и също според Stack Overflow.
Еднакви са, но DateTime? е по-КПК.
Колкото за Database.SetInitializer() конкретно за MigrateDbToLatestVersion, някой може ли да обясни защо да не е добре да се вика в конструктура?
@Tr00peR, защото нямаш гъвкавост, ако искаш няколко приложения да рънват със същия контекст, но с различни миграции. Като цяло по-правилното място на този Database.SetInitializer е в конструктора, защото чисто логически там е логиката, която е свързана с базата. Причината да се слага в стартиращия метод на приложението е посочената по-горе. :)
@petrovaliev95, абсолютно едно и също нещо са DateTime? и Nullable<DateTime> за компилатора. Използва се DateTime?, защото се пише доста по-бързо. :)
@petrovaliev95, connection string-ът трябва да го имаш само в приложението, в което ти е главния стартиращ се метод Main или Application_Start. Там се съхраняват всички настройки, от които има нужда приложението, докато работи, дори и част от тях да се ползват в други dll-ки, които си писал в него. ;)
Относно мястото на Database.SetInitializer() открих, че трябва да ти е преди инстанцирането на DBContext, защото ако нямаш таблица при създаването на таблицата не ти сработва seed метода. След повторно ръннване и налична база се изпълнява без проблем.
Няма ли начин да се провери дали е променяна схемата и ако не е да не се вика seed метода?
Или попаднах на твоето домашно или на някой, който е копирал едно към едно от теб, надявам се да е първото. Реших, че ще полезно да напиша коментар за домашното, като се надявам и този, който е копирал, ако има такъв да го прочете.
http://stackoverflow.com/questions/6062192/there-is-already-an-open-datareader-associated-with-this-command-which-must-be-c
Нещото, което можеш да направиш е да извикаш .ToList() като теглиш студентите. Като това има малък проблем, който води до следващата точка.
Snippet
Като за да имаш Include() трябва да се добави System.Data.Entity, което го имаш само го отбелязвам.
Хареса ми, че ползвал EF Fluent Api за да си направиш типа на полето за датата.
Браво за старанието. И продължавай напред.
Благодаря ти за feedbacka. Значи първо при мен не гърми нищо, всичко си върви по вода.
Connection стринга - имах много главоболия с него копирах някакви неща трих и накрая така е останало, иначе да не е правилно. SeeD метода целта ми беше да го имплементирам в решението си, а не да имам такава логика, че да проверявам дали вече има такива записи. Метода Include() след лекцията по EF performance вече и аз го знам и знам каква е причината да го ползваме. С датите също имах много проблеми (EF попринцип не харесва датите).
За жалост домашното което си оценил не е моето!
Още един път благодаря за изчерпателния feedback.
Поздрави,
Даниел Петровалиев
С такъв коментар бих искал и на моето домашно да попаднеш. Независимо дали аз съм го предал или някой друг от мое име :) Евала за коментара!