piątek, 11 stycznia 2013

70-516 Bezpołączeniowy model

Zacznę od wyjaśnienia samego tytułu, gdyż może być mylący. Stwierdzenie "bezpołączeniowy model" mogłoby sugerować, iż między źródłem danych a samymi klasami nie występuje zależność. Nic bardziej mylnego. Bezpołączeniowy model oznacza, iż klasy odpowiedzialne za obsługę danych są w stanie działać bez ciągłego połączenia z źródłem danych. Jeżeli będziemy chcieli pobrać świeżą paczkę danych, klasy te nawiążą połączenie, pobiorą potrzebne dane, a następnie zakończą połączenie.

Spójrzmy na diagram:


Przedstawiony powyżej diagram przedstawia klasy, wchodzące w skład bezpołączeniowego i połączeniowego modelu.
W tym poście zajmiemy się bezpołączeniowym modelem danych.

DataTable
Obiekt klasy DataTable przedstawia tabelę (np. bazy danych) jako obiekt w pamięci. Obiekt ten przechowuje kolumny jako instancje klasy DataColumn oraz wiersze zawierające dane - DataRow. Tabeli możemy nadać nazwę, co w późniejszym czasie ułatwia jej pobranie z kolekcji tabel.
Każda kolumna przechowywana w DataTable może posiadać dodatkowe ograniczenia związane z rodzajem przechowywanych w niej danych. Dzięki temu, zapewniamy integralność przechowywanych danych.
Niektóre właściwości oraz ich domyślne wartości dla obiektu DataColumn:
  • DataType - typ przechowywanych danych - domyślnie string
  • MaxLength - maksymalna długość w przypadku łańcuchów tekstowych - domyślnie -1 co oznacza brak sprawdzania tego parametru
  • Unique - wartości unikalne - domyślnie false czyli brak kontroli przed wstawianiem duplikatów wartości
  • AllowDBNull - wartości DBNull - domyślnie true czyli nie trzeba specyfikować dla danej kolumny wartości
  • Caption - tytuł kolumny wykorzystywany np. w kontrolkach graficznych typu DataGridView - domyślnie przyjmuje wartość ColumnName
Przykład stworzenia obiektu DataTable:

Code:
            var clientTable = new DataTable("Client");
            var idColumn = new DataColumn("Id");
            idColumn.DataType = typeof (int);
            idColumn.Unique = true;
            idColumn.AllowDBNull = false;
            idColumn.Caption = "ID";
            clientTable.Columns.Add(idColumn);

            var firstNameColumn = new DataColumn("FirstName");
            firstNameColumn.DataType = typeof (string);
            firstNameColumn.MaxLength = 50;
            firstNameColumn.AllowDBNull = true;
            firstNameColumn.Caption = "Imię";
            clientTable.Columns.Add(firstNameColumn);

Do tabeli możemy także dodać informacje mówiące która kolumna/kolumny tworzą klucz główny (Primary Key) oraz ustawić automatycznie numerowane kolumny. Klucz główny wskazujemy za pomocą właściwości PrimaryKey:

Code:
clientTable.PrimaryKey = new DataColumn[] {idColumn};

Auto numerowanie konfigurujemy za pomocą trzech właściwości:
  • AutoIncrement - flaga mówiąca czy auto numerowanie jest włączone dla danej kolumny
  • AutoIncrementSeed - wartość od której się rozpocznie auto numerowanie
  • AutoIncrementStep - krok, o który zwiększy się kolejna wartość w stosunku do poprzedniej
Dla kolumny id, auto numerowanie możemy włączyć w następujący sposób:

Code:
            idColumn.AutoIncrement = true;
            idColumn.AutoIncrementSeed = 1;
            idColumn.AutoIncrementStep = 1;

Nasuwa się pytanie: co się stanie jeżeli w bazie danych także dane pole jest ustawione jako auto numerowane? Otóż wartości automatycznie wyliczane nie są przekazywane do bazy. Baza danych sama wyznaczy kolejne wartości dla pola auto numerowanego. Następnie zostanie uaktualnione pole w obiekcie DataTable wartością pobraną z bazy danych. Istnieje jednak ryzyko: jeżeli nasz DataTable jest numerowany np. od 1 do 50 a w tabeli bazodanowej jest już 10 będziemy mieli do czynienia z następującym scenariuszem:
  • do bazy danych zostanie dodany nowy rekord
  • baza danych wyznaczy dla niego wartość id = 11
  • obiekt DataTable będzie chciał uaktualnić wartość pola kolumny id na 11
  • z powodu istnienia w tabeli rekordu z id = 11, zostanie rzucony wyjątek
Jak zabezpieczyć się na taką ewentualność? Można ustawić wartość właściwości AutoIncrementSeed oraz AutoIncrementStep na -1. Dzięki temu będą generowane wartości ujemne. W większości baz danych identyfikatory dla wierszy są wartościami dodatnimi więc nie pojawi się konflikt z istniejącymi wartościami w bazie, a uaktualnianie wartości w DataTable nie spowoduje konfliktów związanych z auto numerowaniem.

Dodawać dane do DataTable możemy za pomocą metody Add, która została przeładowana i przyjmuje dane w dwóch postaciach:
  • jako obiekt typu DataRow
  • jako tablicę wartości dla poszczególnych kolumn - należy wtedy podać wartość dla każdej kolumny
Innymi metodami umożliwiającymi import wierszy do obiektu DataTable są:
  • ImportDataRow - pozwala na import wiersza z zachowaniem jego stanu
  • Load - pozwala zaimportować nowe wiersze bądź uaktualnić wartości w istniejących
  • LoadDataRow - pozwala wygenerować nowy wiersz na podstawie tablicy wartości dla poszczególnych kolumn
Metoda LoadDataRow oraz Load pozwala wybrać sposób w jaki zostaną dodane/uaktualnione dane w wierszu - odpowiada za to enum  LoadOption, który ma następujące możliwości:
  • OverwriteChanges - nadpisuje dane i zmienia stan wiersza na Unchanged; jeżeli zostanie dodany nowy wiersz - także otrzyma stan Unchanged
  • PreserveChanges - domyślny tryb - nadpisuje oryginalne dane nowymi, ale nie zmienia wersji wiersza. Nowe wiersze będą w stanie Unchanged
  • Upsert - zmienia aktualną wersję, ale nie oryginalną. Nowe wiersze będą mieć stan Added; wiersze ze stanem Unchanged pozostaną w takim stanie jeżeli aktualna wersja jest taka sama jak oryginalna, w przeciwnym wypadku wiersze będą w stanie Modified

Poniżej znajduje się przykład dodawania wierszy do obiektu DataTable za pomocą wcześniej omówionych metod.
Code:
            //Add new row by creating them first
            var row1 = clientTable.NewRow();
            row1["FirstName"] = "Jacek";
            var row2 = clientTable.NewRow();
            row2["FirstName"] = "Patryk";
            clientTable.Rows.Add(row1);
            clientTable.Rows.Add(row2);

            //Using add with values
            clientTable.Rows.Add(new object[] {3, "Sebastian"});

            //LoadData
            clientTable.LoadDataRow(new object[] { 4, "Marek" }, LoadOption.OverwriteChanges);

Brak komentarzy:

Prześlij komentarz