Двата инструмента, двете компоненти
Съвременните ИС се изграждат с архитектура клиент–сървър. В Модул 3 работихме с MS Access — програма, която се опитва да съвмести и двете компоненти в едно. Това става с цената на компромиси: нито функциите за сървърната част достигат нивото, което се иска от професионалистите, нито тези за клиентската (макар при клиентската ограниченията да са по-малки).
Професионалният подход е всяка компонента да се изгради с инструмент, който ѝ дава всичко необходимо. За сървърната част това е MS SQL Server — с основите му вече се запознахме. За клиентската част се връщаме към стар познат: универсалния език C#, с който клиентската компонента става по-ефективна, по-надеждна и най-вече по-удобна за крайните потребители.
Ключово
SQL Server е инструментът за сървърната част, C# — за клиентската. Този урок подготвя срещата им: как един ред от таблица се превръща в обект и кой тип на кой отговаря.
Ред от таблица и инстанция на клас
Обектно-ориентираният подход структурира данните като инстанции на клас от обекти. Ако искаме да обработваме записите от таблицата Student на базата School, създаваме съответен клас:
public class Student
{ public int idStudent; //уникален номер
public string name, surname, family; //име
public string egn; //ЕГН
public DateTime birt_day; //дата на раждане
public string birt_place, district; //място на раждане
public string e_mail, mobile; //ел. поща и телефон
// методи
...
}Инстанцията на такъв клас е естественият начин да представим данните от един ред на таблицата — при едно условие: сигнатурата на класа (редицата от типове на атрибутите) да съответства на сигнатурата на таблицата. Типовете в SQL Server са много повече и по-разнообразни — това е нормално, целта на сървъра е преди всичко съхраняване на данни. Но ако се абстрахираме от разнообразието на текстовите типове и ги заместим със string, структурни разлики няма.
Има обаче две разлики, които трябва да знаеш:
| Таблица в SQL Server | Клас в C# | |
|---|---|---|
| Подредба | редовете са съхранени заедно, в някакъв порядък | всяка инстанция съществува самостоятелно — за еквивалент трябва масив от инстанции или друга структура |
| Поведение | на методите съответстват съхранените процедури, но те не са обвързани с конкретните редове | дефиницията съдържа и данни, и методи за обработката им — капсулирани заедно |
Бележка
Механизъм, който да свърже редовете на една таблица със съхранените процедури така, както капсулирането свързва данни и методи в един клас, просто няма. И това е естествено — двата инструмента имат различни роли.
Конзолно приложение или с графичен интерфейс
В средата MS Visual Studio с C# създаваме два основни вида приложения — конзолни и с графичен интерфейс. Когато става дума за комерсиален продукт — ИС, разработвана по заявка на клиент — почти задължително е тя да е с графичен интерфейс: крайните потребители са свикнали с него и очакват точно такова приложение.
Има смисъл обаче и от конзолни приложения за връзка със сървъра. Освен потребителите, които въвеждат и обновяват данни, важна е и позицията на администратора на базата — той се грижи за целостта, актуалността и предпазването на данните от загуби. Неговите нужди до голяма степен вече се покриват от SSMS, което също е с графичен интерфейс. Затова конзолно приложение за връзка с БД може да потрябва само при много необичайна обработка, каквато в SSMS не е предвидена — а това ще става рядко.
Бележка
В този курс примерите са конзолни по друга причина — браузърът не може да изпълни Windows Forms. Логиката зад една екранна форма обаче е същата: ще я четем и пишем като конзолна програма.
Съответствие на типовете
Числови типове
Съответствието между числовите типове на C# и тези на T-SQL е неблагоприятно — не всеки тип от едната страна има аналог от другата. Затова, ако в базата се съхраняват много големи числови стойности, изборът на тип в програмата иска особено внимание.
| SQL Server | C# | Забележка |
|---|---|---|
bit | няма аналог | може да се използва byte (или bool) |
tinyint | byte | [0, 255] |
smallint | short | [−32768, 32767] |
int | int | [−2 147 483 648, 2 147 483 647] |
bigint | long | най-широкият цял тип и от двете страни |
decimal(p,s) | decimal | интервалът на decimal е по-къс |
money | няма аналог | може да се използва double; за smallmoney — float |
real | float | интервалът на float е по-къс от този на real |
Внимание
Типовете sbyte, ushort, uint и ulong нямат аналог в SQL Server. Обратното също важи — затова преди да избереш тип, погледни интервала от допустими стойности, а не само името.
Текстови типове
Класът string в C# съхранява текстове в 16-битово (2-байтово) представяне — Unicode/UTF-16. В таблиците на SQL Server са допустими както 2-байтовите nchar(n), nvarchar(n|MAX) и ntext, така и 1-байтовите char(n), varchar(n|MAX) и text. При четене от базата и при записване в нея може да се наложи преобразуване на типа.
binary(n)иvarbinary— може иstring, но е разточително след прекодирането с 2-байтова таблица; алтернатива са масиви отbool.image— съхранява обекти със сложно вътрешно форматиране (изображения, звук, видео); съответният тип в C# еBitmap.
Дата, час и специфични типове
C# предоставя специализирания клас DateTime. С него се четат стойностите на атрибути от типовете datetime, datetime2, smalldatetime, date и time — със съответните ограничения, а записването става в някой от първите три. Алтернативата е данните за дата и час да се превръщат в низове, но тогава губиш методите на DateTime.
| SQL Server | В C# |
|---|---|
sql_variant | инстанция на „глобалния“ клас object с последващо преобразуване до подходящ тип |
uniqueidentifier | 16-елементен масив от byte (или 4-елементен от uint, или 2-елементен от ulong) |
xml | низ със специфичен формат — спокойно се пази в string |
Практикум
Задача 1
Припомни си важни моменти от програмирането на C#: как се стартира създаването на конзолно приложение и на приложение с графичен интерфейс, как се създава клас от обекти, как се създават и четат двоични (позаписни) файлове, как се създават екранни форми.
Задача 2
По образеца на класа Student създай класове от обекти, съответни на таблиците на базата от данни, която проектира в предишния раздел.
Въпроси
Кои типове на SQL Server най-трудно ще намерят подходящо представяне в C#? За тип на SQL Server, който липсва в C#, в кой тип да се преобразува — и винаги ли обратното преобразуване е възможно? Как започва преобразуването на стойност от един тип в друг в C#?
Какво трябва да запомниш
- SQL Server изгражда сървърната компонента, C# — клиентската; Access съвместява двете с цената на компромиси.
- Един ред от таблица се представя от инстанция на клас, стига сигнатурата на класа да съответства на сигнатурата на таблицата.
- Таблицата е съвкупност от подредени редове — в C# ѝ съответства масив от инстанции, а не единичен обект.
- Класът капсулира данни и методи заедно; в базата на методите съответстват съхранените процедури, но те не са обвързани с редовете.
- Съответствието на числовите типове е непълно — проверявай интервала от допустими стойности, а не името на типа.
stringе 2-байтов (UTF-16), а в базата има и 1-байтови текстови типове; за дата и час се ползваDateTime.