W poprzednim poście rozpocząłem omawianie obiektu
DataTable. W tym poście kontynuuje rozpoczęty temat.
Stan wiersza
Wiersze w obiekcie
DataTable zmieniają swoje podczas całego życia obiektu. Sprawdzając właściwość
RowState możemy dowiedzieć w jakim stanie jest obecnie wiersz. Wartości tego typu wyliczeniowego:
- Detached - wiersz został stworzony, ale nie dodany do tabeli
- Added - wiersz został stworzony i dodany do tabeli
- Unchanged - stan wiersza nie zmienił się od ostatniego wywołania metody AcceptChanges; w momencie wywołania metody AcceptChanges wiersz przyjmuje ten stan
- Modified - wiersz zmienia się w ten stan tylko jeżeli poprzednio miał stan Unchanged; po wywołaniu AcceptChanges wiersz zmienia swój stan na Unchanged
- Deleted - wiersz przyjmuje ten stan gdy zostanie usunięty z tabeli
Przykład obrazujący zmianę stanów wiersza:
Code:
static void Main(string[] args)
{
var clientTable = new DataTable("Client");
var idColumn = new DataColumn("Id");
idColumn.DataType = typeof (int);
idColumn.Unique = true;
idColumn.AllowDBNull = false;
idColumn.Caption = "ID";
idColumn.AutoIncrement = true;
idColumn.AutoIncrementSeed = 1;
idColumn.AutoIncrementStep = 1;
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);
clientTable.PrimaryKey = new DataColumn[] {idColumn};
var row1 = clientTable.NewRow();
row1["FirstName"] = "Jacek";
Console.WriteLine(row1.RowState);
clientTable.Rows.Add(row1);
Console.WriteLine(row1.RowState);
row1["FirstName"] = "Marek";
Console.WriteLine(row1.RowState);
row1.AcceptChanges();
Console.WriteLine(row1.RowState);
row1["FirstName"] = "Sebastian";
Console.WriteLine(row1.RowState);
row1.RejectChanges();
Console.WriteLine(row1.RowState);
Console.WriteLine(row1["FirstName"]);
row1.Delete();
Console.WriteLine(row1.RowState);
}

Zarządzanie danymi w wierszu za pomocą wersji wiersza
DataTable może posiadać do trzech wersji danego wiersza: oryginalny (
Original), obecny (
Current) oraz zaplanowany (
Proposed). Możliwe wartości przechowywane są w enumie
DataRowVersion:
- Current - obecna wartość; istnieje zawsze oprócz sytuacji w której usuniemy wiersz (próba pobrania zakończy się wyjątkiem)
- Default - jeżeli DataRowState jest ustawiony na Added lub Modified - domyślna wartość to Current; jeżeli Deleted - rzucony zostanie wyjątek; jeżeli zostanie wywołana metoda BeginEdit - Proposed
- Original - wartość załadowana do wiersza, lub ta od ostatniego wywołania metody AcceptChanges. Wartość ta nie jest ustawiana dopóki wiersz nie znajdzie się w stanie Modified, Unchanged, lub Deleted. Jeżeli wiersz jest w stanie Added, zostanie rzucony wyjątek VersionNotFound
- Proposed - wartość w trakcie edycji wiersza. Jeżeli wiersz jest w stanie Deleted, zostanie rzucony wyjątek. Jeżeli metoda BeginEdit nie została wywołana, bądź też została wywołana na wierszu, który nie należy do DataTable, zostanie rzucony wyjątek VersionNotFound
Za pomocą metody
HasVersion możemy w bezpieczny sposób sprawdzić czy dana wersja jest dostępna. Przykładowy kawałek kodu pozwalający na bezpieczne pobranie danej wersji wiersza:
Code:
foreach (var rowVersion in Enum.GetNames(typeof(DataRowVersion)))
{
var enumValue = (DataRowVersion)Enum.Parse(typeof (DataRowVersion), rowVersion);
if (row1.HasVersion(enumValue))
{
Console.WriteLine(enumValue + " " + row1["FirstName", enumValue]);
}
}
Metody AcceptChanges oraz RejectChanges
Metody te, jak same ich nazwy mówią służą do akceptacji lub odrzucenia danych. Metody te są potrzebne, aby zmienić stan wiersza na
Unchanged.
Po dokonaniu zmian wierszy, które zostały pobrane z źródła danych (np. bazy danych) należy wybrać tylko te wiersze, których stan to
Modified. Wiesze które zostały zmodyfikowane możemy pobrać za pomocą metody
GetChanges. Po zapisaniu zmian do źródła danych należy wywołać metodę
AcceptChanges w celu zresetowania stanu wierszy przechowywanych w obiekcie
DataTable.
Wywołanie
AcceptChanges dodatkowo powoduje skopiowanie danych z wersji
Current do wersji
Original.
Wywołanie
RejectChanges powoduje skopiowanie danych z wersji
Original do
Current.
Stan wiersza możemy także zmienić za pomocą dwóch dodatkowych metod:
- SetAdded - dodany
- SetModified - zmodyfikowany
Operacja taka może być przydatna gdy chcemy dane zapisać do innego źródła danych niż z którego oryginalnie zostały pobrane. Wystarczy w takim przypadku wywołać metodę
SetAdded i przesłać taki obiekt
DataTable do
DataAdapter-a.
Metody te mają ograniczenie do wywoływania ich na wierszach, które są w stanie
Unchanged. Jeżeli wiersz jest w innym stanie, zostanie rzucony wyjątek
InvalidOperationExcetpion.
Dodatkowo metody te:
- SetAdded - usuwa oryginalną wersjędanych
- SetModified - nie modyfikuje wersji wiersza
Usuwanie wierszy i cofanie tej operacji
Wywołując metodę
Delete na wierszu oznaczamy go do usunięcia. Następstwem jest usunięcie wersji danych
Current oraz
Proposed.
Jeżeli okaże się, że dany wiersz ma nie być usunięty, można użyć metody
RejectChanges. Dane
Original zostaną skopiowane do
Current. Wiesz wraca do stanu sprzed ostatniego wywołania metody
AcceptChanges, jednak wszystkie operacje wykonane po tej metodzie nie zostaną przywrócone.
Iteracja po danych zawartych w DataTable
Po obiekcie
DataTable można iterować za pomocą pętli:
Code:
var productTable = new DataTable("Products");
productTable.Columns.Add("Id", typeof (int));
productTable.Columns.Add("Name", typeof(string));
productTable.Columns.Add("Price", typeof(decimal));
productTable.Columns.Add("Amount", typeof(int));
productTable.Rows.Add(new object[] { 1, "Laptops", 1678, 100 });
productTable.Rows.Add(new object[] { 2, "Printers", 234.6d, 40 });
productTable.Rows.Add(new object[] { 3, "Keybords", 70.30d, 130 });
foreach (DataRow row in productTable.Rows)
{
foreach (DataColumn column in productTable.Columns)
{
Console.Write(row[column.ColumnName] + " ");
}
Console.WriteLine();
}
Kopiowanie obiektów DataTable
Obiekty
DataTable można kopiować za pomocą dwóch metod:
- Copy - tworzy kopię zawierającą schemat i dane
- Clone - kopiuje tylko schemę
Jeżeli zdecydujemy się na metodę
Clone, możemy za pomocą metody
ImportRow skopiować do niej wybrane rekordy (należy pamiętać, że schema tabel musi być taka sama). W przypadku gdy do tabeli docelowej będziemy próbowali skopiować rekord z kluczem głównym, który już w niej występuje, zostanie wyrzucony wyjątek
ConstraintException.
Przykładowy kod do pobrania:
http://sdrv.ms/X0ZixZ