Ползване на SQL Express / SQL Server на изпита


3
Няколко пъти става на въпрос, че при peer review може да се появят проблеми заради ползването на различните видове SQL сървъри Express или Standard в C# application-а, тъй като connection string-овете за двата са различни и ако си правил задачата на Express и някой се опитва да я проверява на стандартния няма да тръгне без да промени string-a в app.config.
Пробвах различни начини да се справя с това още на задачите за домашното, но се сбъсках с един основен проблем. В DbContext наследника, който ние си създаваме можем да заложим като параметър в конструктора при извикването на :base, името на съответния connection string и по този начин да изберем вида сървър директно в програмата. Проблема идва от това че EF явно при инициализацията на контекста, чрез рефлешън извиква многократно конструктора на нашия контекст и то базовия parametterless конструктор, тоест дори да сме си направили наш си в който да подаваме connection name като параметър то при първото използване на контекста след EF ще почне да си вика базовия конструктор без параметри, което ще презапише connection-а който ние сме подали.
Решението, което аз ползвам е да добавя едно статично property в контекст класа, примерно public static string ConnectionName {get; set;} и да модифицирам базовия конструктор public MyContext() : base(ConnectionName).
Така преди създаването на MyContext обект трябва да извикаме MyContext.ConnectionName = connectionNameConstant; като константата е името на конекцията, която искаме да използваме. Така в програмата може през потребителския интерфейс да попитаме потребителя какъв SQL сървър ползва, вместо да го караме да редактира/добавя connection string-ове в app.config (разбира се ние предварително трябва да сме ги добавили там - за SQL Server за SQL Express и евентуално и за localDb). Разбира се това решение не е идеално от към качество на кода, защото правим зависимост на работата на класа от статично property, но поради начина по който EF си инициализира контекста аз успях да стигна само до това решение. Трябва също така да се има в предвид, че ако не подадем в ConnectionName никакъв стринг преди да извикаме конструктура ще гръмне с грешка, защото базовия конструктор на DbContext ако е извикан с параметър connectionName иска той да не е null или empty.
Въпреки кофти практиката да се връзваме към статични свойства в случая има смекчаващи "вината" обстоятелства, които можем да ползваме :). Ако реализацията ни е през Repository и Unit Of Work патерни там изискването е да ползваме само един контекст, което се гарантира от тях. Тоест можем в инициализацията им да направим конструктори ползващи за параметър името на конекцията и да си гарантираме, че там където създаваме инстанцията на DbContext ще подадем на статичното пропърти съответния стринг и след това ще си викнем конструктора на DbContext.
Получи се малко дълго описание, но се надявам да е полезно. Ще се радвам, ако някой е измислил по умен вариант на подобна инициализация на конекцията да го сподели.

в Databases от ivand (862 точки)


Отговори



6

От бъдещите програмисти ще се очаква поне малко да могат да мислят и да могат да си сменят connection stringa. Ако това елементарно нещо някой не може то за какви сертификати се бори и за каква работа в IT индустрията?

Все пак проверката е нож в 2 остриета. Би трябвало да се оцени и знанието/незнанието на проверяващия до колко може да смени един connection string.

public class ApplicationDbContext : DbContext

    {
        private static string _connection;
 
        public ApplicationDbContext()
            : base(_connection ?? "appContext")
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Migrations.Configuration>());
        }
 
        public ApplicationDbContext(string connection)
            : base(connection)
        {
            _connection = connection;
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Migrations.Configuration>());
        }
}
 
var Context = new ApplicationDbContext([userchoice]);
 
Репозирай си го :)

от saykor (8845 точки)


0
Това че всеки трябва да може да сменя connection string е така и works in theory, ама като доиде проверката все може да се намери някой, който да пусне приложението да му гръмне с exception и директно да нацъка "не работи". Иначе варианта ти е по-добър, директно с параметризирания конструктур, подобно го бях направил в някакво домашно, само че явно съм забавил за оператора ?? :)

от ivand (862 точки)

0
Дам. Помня тръпката по проверките дали няма да се случи точно това дето описваш.
Това го ползвам в WPF програма. Клиента избира с коя компания да се логне и то му сменя connectionstring-a според нея.

от saykor (8845 точки)