Професионална програма
Loading...
+ Нов въпрос
ttitto avatar ttitto 1154 Точки

[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 часа, докато разбера коя валидация ми пищи.

Моля, не копирайте домашното дословно в системата и не го качвайте като собствено!

4
Databases Basics 09/03/2015 16:32:59
VGeorgiev avatar VGeorgiev 1385 Точки

Seed метода от Configuration си се извиква. Само трябва да run-неш SetInitializer-a.

Database.SetInitializer(new MigrateDatabaseToLatestVersion<StudentSystemDbContext, Configuration>());

4
ttitto avatar ttitto 1154 Точки

Благодаря! Аз съм пробвал да извикам SetInitializer в конструктора на StudentSystemDbContext и вероятно затова не е сработило. Затова порових в гугъл и намерих вариант с допълнителен клас, който работи. Като цяло цял ден странни неща ми се случваха с този Code First ;)

0
petrovaliev95 avatar petrovaliev95 358 Точки

Най-накрая тема и за това домашно.

Ето моите творения - ЦЪК.

Относно 'connection' стринговете и на мен ми беше много странно, че трябва да ги добавям във всеки проект който ползва контекста.
Имам един въпрос относно "Database.SetInitializer()" метода.
Къде е правилното място да го викаме този метод, аз лично в "Main" метода го извиквам.

 

Поздрави,

Даниел Петровалиев

1
borislavml avatar borislavml 368 Точки

И според мен е "по-правилно" да се вика в main-а на конзолния клиент. Ако го сетнеш в DbContext конструктора, други клиенти (web, desktop) ще са длъжни да ползват същия migration. Пак според нуждите smile

0
VGeorgiev avatar VGeorgiev 1385 Точки

В моделите няма нужда да добавяш connection string-a.

Database.SetInitializer() го слагаш там където ти е началната точка на Application-a. Примерно в ASP.NET MVC проект го слагаш в Global.asax в Application_Start. В конзолен проект в Main методa.

2
08/03/2015 22:56:09
petrovaliev95 avatar petrovaliev95 358 Точки

@VGeorgiev
Оо да това е copy-paste грешка. Понеже ми гърмеше и аз навсякаде копирах "App.config" файловете.

Колкото до това да сложим "Database.SetInitializer()" в конструктора на контекста - Това си е чист "StackOverflow Exception".

0
08/03/2015 22:52:16
borislavml avatar borislavml 368 Точки

Вчера цяла вечер си блъсках главата във връзка с условието в домашното : Configure the EF to run the seed method after the database is created for a first time. Run the application several times to ensure that it seeds sample data only once.

След доста четене из stack overflow и тази изключително интересна и полезна статия ЦЪК, се оказа, че Database.SetInitializer и Seed метода са пряко обвързани и първия вика втория винаги. Ако се ползва DropCreateDatabaseAlways стратегия за миграция, няма проблем със сийда защото така или иначе базата се прави на ново при всеки  run  на приложението, но при MigrateDatabaseToLatestVersion има поблем, защото сийд-а ще пълни всеки път. Та във връзка с изискването базата да се се сийд-ва само при инициализация, човечеца в статията (явно ги понаразбирва нещата) предлага два варианта: 

1. Ползва се метода AddOrUpdate - context.Students.AddOrUpdate (studentGosho); в сийд метода.  Това обаче е супер бавно, ще проверява всяка таблица и всяко ентри в нея и ако има 2000 реда код в сийд-а, ще стане майка си и баща си.

2. Проверява се в сийд метода има ли някой в конкретната таблица и връщаме ако има - if (context.Students.Any()) return  

Аз се спрях на второто решение, но и двете не ми харесват. Въпроса ми е дали в EF6 не са измислили нещо по-умно. Примерно в main метода след Database.SetInitializer, някак си да се прави тази проверка и да се спре изискването на Seed, или щом EF го вика няма как да го спрем? Ще се радвам, ако някой знае или е имислил нещо, и сподели.smile

6
vladislav.karamfilov avatar vladislav.karamfilov 1123 Точки

Да, решението ти е (context.Students.Any()) return; :)

2
ZvetanIG avatar ZvetanIG 917 Точки

Здравейте, колеги и аз се включвам с моето домашно.

Иначе и аз имах проблеми с този Seed.  Не искаше да пълни данните при първоначалното създаването на базата, но след като го сложих над инстанцията на контекста, заработи. Но така и не намерих начин да го накарам да се изпълнява само веднъж и да не ми дублира записите. А за това аз да си проверявам дали данните са налични изобщо не се сетих. През цялото време си мислих, че има по-умен начин.

2
09/03/2015 22:53:18
Jazastry avatar Jazastry 51 Точки

Едно домашно и от мен GitHub. Исползвах всички препоръки от предноте постове и всичко работи :).

Ако някой има проблем с намирането на (localdb) във VIsualStudio2013 е (localdb)\MSSQLLocalDB.

Ако някой е без Resharper, като мен, нужно е да се добави  using System.Runtime.InteropServices.ComTypes; в конзолния клиент за да може да се исползва  Database.SetInitializer метода.

4
F08041A avatar F08041A 5 Точки

Здравейте,

Моля някой с повече опит да обясни защо когато инстанцираме колекция в конструктора на някой клас, не минаваме през пропъртито, а инстанцираме самото прайвът поле. Нали по принцип се минава през пропъртито, за да се извърши някаква валидация, ако е нужно.

 

private ICollection<Course> courses;

public Student()
{

     this.courses = new HashSet<Course>();

}

public int Id { get; set; }

public string Name { get; set; }


public virtual ICollection<Course> Courses
{
   get
  {
       return this.courses;
  }
 set
 {
          this.courses = value;
 }
}

Имам спомен, че в случая с рефернтните типове в даден клас, въпреки че има прайвит поле и пропърти, при наследяване на класа някой може да достъпи полето (колекцията) и да изтрие данните в нея. Така ли е?

0
petrovaliev95 avatar petrovaliev95 358 Точки

В случая не виждам да трябва валидация така, че за какво ти е? 
При наследяване "private" полето не съм чувал някъде да се наследява.

0
F08041A avatar F08041A 5 Точки

Виждам, че някои колеги използват в конструктора пропъртито, а други прайвът полето...затова питам, каква е разликата?

 

0
borislavml avatar borislavml 368 Точки

Ако искаш да не ти ги трият можеш да върнеш нова колекция в getter-a -  return  new List<Course> (this.courses).

Но това така или иначе са данни в памета на приложението и не виждам много смисъл, тези от базата няма как да ти ги пипат. smile

0
Ventsislav avatar Ventsislav 343 Точки

Ето едно домашно и от мен. Споделям го малко по-късно, но нека го има laughing

0