Warstwa dostępu do danych Architektura ADO.NET Obiekty DataSet, Connection, Command, DataAdapter i ich współdziałanie Praca w trybie połączonym: DataReader Praca w trybie odłączonym: DataSet Modyfikacje źródła danych Obsługa procedur pamiętanych w b.d. Integracja z XML Transakcje LINQ, Entity Framework ADO.NET Data Services Mainframe Directory RDBMS Email i wiadomości System plików ADO OLE DB XML Problemy Modele programistyczne Połączeniowy (connected) – oparcie o otwarte połączenia do systemu bazy danych (OLE DB, ADODB) Bezpołączeniowy (disconnected) – pytanie/odpowiedź, bez-stanowy między zapytaniami (HTTP) Obsługa stanu set- based logic to access data from a data source – SQL (LINQ) object orientation to apply business logic to data - service orientation to communicate data using messages across a network Whereas set- based logic is used to access data, object orientation is used to provide a representation of that data to some real- world entities (objects). Data as it is stored in a database does not describe the behavior of that information. You could have customers modeled in a Customer table in SQL Server, each with a customer type, such as buyer and vendor. Clearly, some ways in which you need to interact with buyers and vendors will be the same, as they are both customers; but in other ways, the business rules you use with buyers may well differ from those customers who are vendors. There is clearly a need to map the data between its representation in a table and its representation in an entity (object relational mapping - ADO.NET Entity Framework). The concept of service orientation is delivered using Windows Communication Foundation (WCF), and ADO.NET Data Services. ADO.NET obsługuje dwa model dostępu do danych: Tryb połączony (połączeniowy), Odłączony (bezpołączeniowy) Obiekt recordset z ADO 2.x może on utrzymywać połączenie bazą podczas jednokierunkowego przetwarzania zbioru rekordów lub wczytać zestaw rekordów do znajdującego się po stronie klienta przechowywanego pamięci operacyjnej kursora rozłączyć się bazą. ADO: uproszczony dostęp do danych dla programisty OLE DB: uniwersalny dostawca danych (provider) XML: reprezentacja i modyfikacja danych oparta na standardach Connection-oriented Access Connectionless Access, Database Access with DataAdapter, Integration with XML
Możliwe niepotrzebne zużycie zasobów Tryb połączeniowy W modelu klient – serwer każdy klient łączy się z bazą podczas startu aplikacji i zwalnia połączenie podczas jej zamykania Serwer musi utrzymywać oddzielne połączenia dla każego klienta Możliwe niepotrzebne zużycie zasobów idle busy Serwery bazodanowe zapewniają dostęp do kursora przechowującego stan aktualnego wiersza Dostęp do danych Przesuwanie się przez MoveNext oraz MovePrevious idle Serwer Klienci Połączenia Tabele Wyniki zapytania Kursor rs Klient Serwer Universal Data Access ActiveX Data Objects (ADO) was created to provide ‘Universal’ data access through a single set of objects
Tryb połączeniowy Zalety Wady Połączenie tworzymy tylko raz Możemy ustawiać zmienne powiązane z ‘sesją’ Szeroki dostęp do mechanizmów zabezpieczajacych dostarczonych przez bazę danych Pierwszy wiersz zapytania dostępny od razu Niepotrzebne zużycie zasobów Problemy ze skalowalnością Nie dostosowany do aplikacji webowych Użytkownicy się nie wylogowują Wahająca się liczba użytkowników Nie dostosowany do aplikacji wielowarstwowych
Zasoby są używane tylko gdy są potrzebne Tryb bezpołączeniowy Połączenia są zwalniane zaraz po wykorzystaniu Obiekty danych wykorzystywane są również po zwolnieniu połączenia Połączenie jest nawiązywane by zapisać zmiany do bazy idle Zasoby są używane tylko gdy są potrzebne Serwer busy Dane są dostarczane do klienta w jednej operacji Wyniki zapytania przechowywane w pamięci klienta Zasoby serwera są zwalniane Klient zarządza danymi w trybie off-line Ponowne połączenie z bazą by zapisać zmiany Połączenia idle Klienci Wyniki zapytania Kursor Klient rs Serwer Tabele Universal Data Access ActiveX Data Objects (ADO) was created to provide ‘Universal’ data access through a single set of objects
Tryb bezpołączeniowy Zalety Wady Mniejsze zużycie zasobów serwera Modyfikacja danych jest szybsza i bardziej elastyczna Dane nie związane z połączeniem Łatwe przekazywanie między warstwami Wykorzystywane w aplikacjach wielowarstwowych oraz webowych Otwieranie i zamykanie połączeń jest kosztowne Wczytywanie dużych ilości danych jest czasochłonne Zużycie zasobów po stronie klienta Mniej opcji zarządzania bezpieczeńswem
Architektura ADO.NET .NET Data Provider DataSet Tables Connection Transaction Command Parameters DataReader DataAdapter SelectCommand InsertCommand UpdateCommand DeleteCommand DataSet Tables DataTable DataRowCollection DataColumnCollection ConstraintCollection DataRelationCollection Fill Update Database Connection-oriented Keeps the connection to the data base alive Intended for applications with: short running transactions, only a few parallel accesses , up-to-date data Connectionless No permanent connection to the data source Data cached in main memory Changes in main memory changes in data source Intended for applications with: many parallel and long lasting accesses (e.g.: web applications) What Is a Connected Environment? A connected environment is one in which users are constantly connected to a data source Advantages: Environment is easier to secure, Concurrency is more easily controlled, Data is more likely to be current than in other scenarios Disadvantages: Must have a constant network connection, Scalability What Is a Disconnected Environment? In a disconnected environment, a subset of data from a central data store can be copied and modified independently, and the changes merged back into the central data store Advantages: You can work at any time that is convenient for you, and can connect to a data source at any time to process requests, Other users can use the connection, A disconnected environment improves the scalability and performance of applications Disadvantages: Data is not always up to date, Change conflicts can occur and must be resolved ReadXml WriteXml XML .NET data provider jest to zestaw klas, za pomocą których podłaczamy się do źródła danych oraz pobieramy i aktualizujemy dane
ADO.NET Object Model .NET Data Provider DataSet DataTable DataColumn DataRow Constraint DataRelation Connection Command Parameter DataReader Transaction DataAdapter .NET Data Provider Klasa Opis Connection Umożliwia nawiązanie połączenia z określonym źródłem danych Command Wywołuje polecenie na źródle danych. Udostępnia kolekcję parametrów (Parameters) i zawsze działa w kontekście otwartego połączenia (Connection) DataReader Udostępnia jednokierunkowy (rekord po rekordzie) strumień danych ze źródła, w trybie 'tylko do odczytu' DataAdapter Wypełnia DataSet danymi pochodzącymi ze źródła oraz umożliwia aktualizacje danych w źródle na podstawie DataSet-u (kanał łączący obiekt DataSet z dostawcą danych) IDataCommand Wykonanie polecenia, parametry itp IDataReader Jednokierunkowy kursor tylko do odczytu. Generowany przez IDataCommand DataSet De facto baza danych po stronie aplikacji klienckiej. Filtry, wyszukiwanie, dodatkowe wyrażenia Wypełniany przez IDataAdapter Polecenia IDataCommand W „środku” wykorzystuje IDataReader XML Synchronizacja (uaktualnianie danych). Dotyczy różnych DataSet, źródła danych itp Transakcje: SQLTransaction/OleDbTransaction – pobiera się z połączenia a potem dodaje do konkretnej operacji (polecenia IDataCommand; w SQL-u można tworzyć SavePoints (punkty zapisu) DbConnection represents connection to the data source DbCommand represents a SQL command DbTransaction represents a transaction, commands can be executed within a transaction DataReader result of a data base query, allows sequential reading of rows
ADO.NET Class hierarchy Interfejsy IDbConnection IDbCommand IDbTransaction IDataReader Abstrakcyjne klasy bazowe DbConnection DbCommand DbTransaction DbDataReader Implementacja specjalizowana OleDb: implementacja dla OLEDB Sql: implementacja dla SQL Server Oracle: implementacja dla Oracle Odbc: implementacja dla ODBC DbCommand -klasa abstrakcyjna implementująca interfejs IDbCommand
Tworzenie połączenia Łańcuch połączenia (ang. connection string) - ciąg znaków zawierających parametry konfiguracji połączenia SqlConnection Parametry ConnectionString Connection timeout: dopuszczalny czas uzyskania połączenia Data source: nazwa instancji SQL Server lub nazwa komputera Initial catalog: nazwa bazy danych Integrated security; gdy True połączenie z SQL serwerem na podstawie tożsamości konta procesu ASP.NET string strConn = "data source=localhost; " + "initial catalog=northwind; integrated security=true"; SqlConnection conn = new SqlConnection(strConn); User ID: konto logowania SQL Server Password: … Persist security info Provider Opening and closing connections explicitly: Open and Close methods Opening and closing connections implicitly: Data adapters can open and close connections automatically when needed Using the Dispose method: Removes the connection from the connection pool Provider The property used to set or return the name of the provider for the connection, used only for OleDbConnection objects. Connection Timeout or Connect Timeout The length of time in seconds to wait for a connection to the server before terminating the attempt and generating an exception. 15 is the default. Initial Catalog The name of the database. Data Source The name of the SQL Server to be used when a connection is open, or the filename of a Microsoft Access database. Password The login password for the SQL Server account. User ID The SQL Server login account. Integrated Security or Trusted Connection The parameter that determines whether or not the connection is to be a secure connection. True, False, and SSPI are the possible values. (SSPI is the equivalent of True.) Persist Security Info When set to False, security-sensitive information, such as the password, is not returned as part of the connection if the connection is open or has ever been in an open state. Setting this property to True can be a security risk. False is the default. http://www.connectionstrings.com/
Połączenie: Tworzenie połączenia public interface IDbConnection { string ConnectionString {get; set;} int ConnectionTimeout {get;} string Database {get;} ConnectionState State {get;} IDbTransaction BeginTransaction(); IDbTransaction BeginTransaction(IsolationLevel il); void ChangeDatabase(string db); void Close(); IDbCommand CreateCommand(); void Open(); } BeginTransaction – Rozpoczyna tranzakcję ChangeDatabase – Zmiana bazy dla otrawtego połącznia ConnectionTimeout – Określenie czasu timeoutu połączenia Database – Nazwa bazy dla połączenia Open, Close – Otwieranie i zamykanie połączenia State – Zwraca stan aktualnego połączenia: Broken, Closed, Connecting, Executing, Fetching, or Open. CreateCommand – Tworzy obiekt Command powiązany z połączeniem
ConnectionString - zarządzanie Umieszczamy w sekcji <connectionStrings> pliku konfiguracyjnego < configuration > ... < connectionStrings > < add name=”Northwind” providerName=”System.Data.SqlClient” connectionString=”server=(local); integrated security=SSPI;database=Northwind” / > < /connectionStrings > < /configuration > private DbConnection GetDatabaseConnection ( string name ) { ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[name]; DbProviderFactory factory = DbProviderFactories.GetFactory(settings.ProviderName ); DbConnection conn = factory.CreateConnection ( ) ; conn.ConnectionString = settings.ConnectionString ; return conn ; } C:\Windwos\\Microsfot.NET\Framework\v2.0.50727\CONFIG\machine.config This may seem like a lot of unnecessary work to obtain a database connection, and indeed it is if your application is never going to run on any other database than the one it was designed for.
Wydajne używanie połączeń Blok using try { using (SqlConnection conn = new SqlConnection(source)) // Open the connection conn.Open ( ) ; DoSomething(); } catch (SqlException e) // Log the exception try . . . catch . . . finally try { // Open the connection conn.Open(); DoSomething(); } catch ( SqlException ex ) //Log the exception finally conn.Close ( ) ; The following code demonstrates how to use the using clause to ensure that objects that implement the IDisposable interface are cleared up immediately after the block exits using – zapewnia wywołanie Dispose() najwcześniej jak to możliwe, poprzez zdeklarowanie używanych obiektów i określeniu przez nawiasy {} zasięgu tych obiektów
Pula połączeń Connection pooling – proces utrzymywania otwartych połączeń i ponownego ich reużycia dla uzytkownika lub kontekstu Parametry ConnectionString dla poolingu Connection Lifetime: długość oczekiwania połączenia na ponowne użycie Max Pool Size: maksymalna liczba połączeń Min Pool Size: Minimalna liczba połączeń Pooling: True/False … cnNorthwind.ConnectionString = _ "Integrated Security=True;" & _ "Initial Catalog=Northwind;" & _ "Data Source=London;" & _ "Pooling=True;" & _ "Min Pool Size=5;" & _ "Connection Lifetime=120;" What Is Connection Pooling? Each time you establish a connection to a data source, cycles and memory are used. Because applications often require multiple connections with multiple users, connecting to a data source can be resource-intensive. By pooling connections, you can keep connections available for reuse, which enhances application performance and scalability. Connections with identical connection strings are pooled together and can be reused without reestablishing the connection. A connection pool is created when one or more connections share a unique connection string, and connection-pooling functionality has been requested. Connection pooling is the ability of SQL Server or an OLE DB data source to reuse connections for a particular user or security context. Connection pooling occurs on the computer where the database is installed. Connection Lifetime 0 When a connection is returned to the pool, its creation time is compared with the current time, and the connection is destroyed if that time span (in seconds) exceeds the value specified by connection lifetime. This is useful in clustered configurations to force load balancing between a running server and a server that was just brought online. Connection Reset True Determines whether the database connection is reset when the connection is removed from the pool. Setting this to False prevents an additional server round-trip when obtaining a connection, but you must be aware that the connection state, such as database context, is not being reset. This default option makes the connection change back to its original database context automatically when it is reused. This costs an extra (potentially unnecessary) call to the server. If database contexts will not be changed, set this parameter to False. Use the ChangeDatabase method rather than the SQL USE command to enable ADO.NET to automatically reset connections when they are returned to the pool. Enlist (pozyskiwanie) True When set to True, the pooler automatically enlists the connection in the current transaction context of the creation thread if a transaction context exists. Max Pool Size 100 The maximum number of connections allowed in the pool. Min Pool Size 0 The minimum number of connections maintained in the pool. Pooling True When set to True, the SqlConnection object is drawn from the appropriate pool, or if necessary, is created and added to the appropriate pool.
ADO.NET – modele programowania ADO.NET zapewnia dostęp do obu typów programowania Połączeniowy Używa obiektów Command i DataReader DataReader służy do odczytu w przód Zmiany/aktualizacje odbywają się przez obiekt Command Bezpołączeniowy Używa obiektów DataSet do przechowywania danych u klienta DataAdapter obsługuje komunikację miedzy obiektemDataSet a serwerem Obiekty DataSet są niezależne od providera Obiekty DataSet są przechowywane oraz przesyłane przez XML ADO.NET Programming Models
Obiekt Command Connection - referencja do obiektu połączenia public interface IDbCommand { string CommandText {get; set;} int CommandTimeout {get; set;} CommandType CommandType {get; set;} IDbConnection Connection {get; set;} IDbTransaction Transaction {get; set;} UpdateRowSource UpdatedRowSource {get; set;} IDataParameterCollection Parameters {get;} void Cancel(); IDataParameter CreateParameter(); int ExecuteNonQuery(); IDataReader ExecuteReader(); IDataReader ExecuteReader(CommandBehavior cb); object ExecuteScalar(); void Prepare(); // Note ExecuteXmlReader (SqlCommand only) } Connection - referencja do obiektu połączenia CommandType - typ polecenia Text – wyrażenie SQL StoredProcedure CommandText - w zależności od wyboru typu plecenia: Text – treść polecenia SQL StoredProcedure – nazwa procedury Parameters Parametry, z którymi zostanie wykonane zapytanie IDbCommand models database commands Supports local transactions, data reader queries, non queries (insert, update, delete), and scalar queries How to Create a Stored Procedure Server Explorer On the View menu, click Server Explorer, or press Ctrl+Alt+S Create a data connection, Click New Stored Procedure, Insert SQL How to Create a Command Object Programmatically On the View menu, click Server Explorer, or press Ctrl+Alt+S, Drag stored procedure onto form or component Toolbox Use SqlConnection or OleDbConnection, Use SqlCommand or OleDbCommand Connection referencja do obiektu połączenia CommandType Typ komendy Text – wyrażenie SQL StoredProcedure CommandText W zależności od wyboru typu komendy: Text – treść polecenia SQL StoredProcedure – nazwa procedury Parameters Jeśli polecenie SQL lub procedura przechowywana potrzebuje do wywołania parametrów to umieszczamy je tutaj
Metody wywołania obiektu Command Zapytanie nie zwraca wierszy Wywołanie ExecuteNonQuery Zwraca liczbę wierszy ‘dotkniętych’ przez zapytanie Zapytania DDL and DCL CREATE, ALTER, DROP, GRANT, DENY, REVOKE Zapytaia DML INSERT, UPDATE, DELETE Zapytanie zwraca pojedynczą wartość Wywołanie ExecuteScalar ExecuteScalar zwraca typ Object Zapytanie zwraca wiersz Metoda ExecuteReader Zwraca obiekt DataReader Reader zależny od providera: SqlDataReader, OleDbDataReader DataReader Służy tylko do odczytu, możliwe przesuwanie tylko w przód Zapytanie zwraca XML ExecuteXmlReader – dostępny tylko dla SQL Server
Command - przykład private void Demo() { SqlConnection con = new SqlConnection( "Server=localhost; Database=Pubs; Integrated Security=SSPI" ); SqlCommand cmd = new SqlCommand( "SELECT COUNT( * ) FROM Authors", con ); con.Open(); Console.WriteLine( cmd.ExecuteScalar() ); // Writes '23' con.Close(); // Important! } Commands execute against a connection Similar to ‘classic’ ADO Command class Can return a DataReader, a scalar value, or nothing Stored procedure, parameter and transaction support
Asynchroniczne wywołanie Command ADO.NET 2.0 wspiera tryb asynchroniczny Wykonanie poleceń w tle IAsyncResult BeginExecuteReader (AsyncCallback callback) IDataReader EndExecuteReader (AsyncResult result) IAsyncResult BeginExecuteNonQuery (AsyncCallback callback) int EndExecuteNonQuery (IAsyncResult result) IAsyncResult BeginExecuteXmlReader (AsyncCallback callback) IDataReader EndExecuteXmlReader (IAsyncResult result)
Asynchroniczny Command - przykład ... public class Async { SqlCommand cmd; //---- command which should be executed asynchronously public void CallCmdAsync() { SqlConnection conn = new SqlConnection( "Data Source=(local)\\NetSDK...; Asynchronous Processing=true"); cmd = new SqlCommand("MyLongRunningStoredProc", conn); cmd.CommandType = CommandType.StoredProcedure; conn.Open(); //---- start asynchronous execution of command cmd.BeginExecuteNonQuery(new AsyncCallback(AsyncCmdEnded), null); } //---- callback method called at the end of the execution of command public void AsyncCmdEnded(IAsyncResult result) { //---- process result of command int affectedRows = cmd.EndExecuteNonQuery(result); Callback when query is finished
Zapytania parametryzowane Command pozwala na definiowanie parametrów wejściowych i wyjściowych Parameter - pola Name: nazwa parametru Value: wartość parametru DbDataType: typ danych Direction: kierunek parametru Input Output InputOutput ReturnValue IDataParameterCollection Parameters {get;}
Zapytania parametryzowane - przykład Zdefiniowanie zapytania SQL Server: Identyfikacja parametru przez „@”(przykład: "@name") SqlCommand cmd = new SqlCommand(); cmd.CommandText = "DELETE FROM Empls WHERE EmployeeID = @ID"; 2. Dodanie parametru cmd.Parameters.Add( new OleDbParameter("@ID", OleDbType.BigInt)); 3. Przypisanie wartości cmd.Parameters["@ID"].Value = 1234; cmd.ExecuteNonQuery();
Tryb połączeniowy: DataReader DataReader – Odczyt strumienia danych zwróconych przez zapytanie Tylko do odczytu w przód Szybki dostęp Praca w trybie połączeniowym Programista zarządza połączeniem i danymi Małe zużycie zasobów public interface IDataReader { int Depth {get;} bool IsClosed {get;} int RecordsAffected {get;} … void Close(); DataTable GetSchemaTable(); bool NextResult(); bool Read(); } Użycie DataReader: Stwórz i otwórz połączenie Stwórz obiekt Command Stwórz DataReader dla obiektu Command Odczytaj dane Zamknij DataReader Zamknij połączenie Użycie w bloku Try…Catch…Finally Read - Advances the IDataReader to the next record Obiekt SqlDataReader jest częścią zarządzanego dostawcy danych, może w jednej operacji odczytać ze źródła danych tylko jeden wiersz i musi stale utrzymywać z tym źródłem połączenie, aby móc odczytać kolejne wiersze. Po uruchomieniu zapytania, do obiektu DataReader zwracany jest za pośrednictwem strumienia pierwszy wiersz wyniku. Strumień pozostaje połączony z bazą danych i jest gotowy na pobranie następnego rekordu. Obiekt DataReader w danej chwili odczytuje tylko jeden rekord i może przesuwać się tylko do przodu, rekord po rekordzie. What is a DataReader? IDataReader models streaming data access Data is read in forward-only streaming mode for speed Reads one row at a time (buffer in network transport) Supports name or ordinal-based column access Supports bulk query resultsets NextResult - Przejście do kolejnego zestawu wyników Read – Przechodzi do następnego rekordu
Praca z IDataReader - przykład IDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { Stwórz obiekt i rozpocznij odczyt object[ ] dataRow = new object[reader.FieldCount]; int cols = reader.GetValues(dataRow); Przeczytaj kolumny do tablicy object val0 = reader[0]; object nameVal = reader["LastName"]; Odczyt za pomocą indekserów string firstName = reader.getString(2); Odczyt za pomocą metod } reader.Close(); Zamknięcie obiektu
Odczyt danych z obiektu DataReader // Open Connection and create command SqlConnection conn = new SqlConnection("data source=localhost; initial catalog=pubs; integrated security=true"); SqlCommand cmdAuthors = new SqlCommand("select * from Authors", conn); conn.Open(); // Create DataReader and read data SqlDataReader dr; dr = cmdAuthors.ExecuteReader(); while (dr.Read()) { lstBuiltNames.Items.Add(dr["au_lname"] + ", " + dr["au_fname"]); } // Close DataReader and Connection dr.Close(); conn.Close(); Wołanie Read dla każdego rekordu Zwraca false gdy brak danych Dostęp do pól Dostęp poprzez indeks lub nazwę Funkcje Get… - najlepsza wydajność Zamknięcie DataReader Zamkniecie połączenia while (myReader.Read()) { str += myReader[1]; str += myReader["field"]; str += myReader.GetDateTime(2); } Reading Data from a DataReader Read method Loads the next row Returns true if a row exists, false if at end of rows Item property GetXxx methods – for example, GetString, GetInt32 GetValues method IsDbNull method Close method
Transakcje Transakcje lokalne Transakcje rozproszone Dostęp z jednego połączenia Udostępnione przez ADO.NET Transakcje rozproszone Wykonywane na wielu połączniacj Użycie Microsoft Distributed Transaction Component (MSDTC) namespace System.Transaction 2 transaction models
Transkacje lokalne ADO.NET wspiera tranzakcyjność Transakcja jest Transakcję rozpoczynamy poprzez metodę BeginTransaction która zwraca obiekt transakcji. Transakcja wspiera metody wykonujące zmiany na bazie danych – polecenia (Command) Transakcja jest Zatwierdzana poprzez Commit Wycofywana poprzez Rollback Local Transactions with ADO.NET. Connection objects support transactions with a BeginTransaction method that creates a transaction object (for example, a SqlTransaction object). The transaction object in turn supports methods that allow you to commit or roll back the transactions.
Transakcje - przykład 1. Definicja 2. Stworzenie obiektów SqlConnection con = new SqlConnection(connStr); IDbTranaction trans = null; try { con.Open(); trans = con.BeginTransaction(IsolationLevel.ReadCommitted); 2. Stworzenie obiektów IDbCommand cmd1 = con.CreateCommand(); cmd1.CommandText = "DELETE [OrderDetails] WHERE OrderId = 10258"; cmd1.Transaction = trans; cmd1.ExecuteNonQuery(); IDbCommand cmd2 = con.CreateCommand(); cmd2.CommandText = "DELETE Orders WHERE OrderId = 10258"; cmd2.Transaction = trans; cmd2.ExecuteNonQuery(); 3. Zatwierdzenie lub cofnięcie wyników trans.Commit(); catch (Exception e) { if (trans != null) trans.Rollback(); } finally { try { con.Close();
Poziomy izolacji Definiują blokady na odczyt i zapis ADO.NET zapewnia różne poziomy izolacji public enum IsolationLevel { ReadUncommitted, ReadCommitted, RepeatableRead, Serializable, ... } ReadUncommitted Dostęp do zablokowanych danych Dirty reads ReadCommitted Odczyt zablokowanych wierszy zabroniony Brak dirty read, może wystąpić phantom row Non-repeatable reads RepeatableRead ReadCommitted bez non-repeatable reads Serializable Dostęp w seriach Najwyższy poziom izolacji Nie występują phantom rows
2.3.3 Tryb bezpołączeniowy: use DataSet Klient tworzy żądanie wyświetlenia strony 1 Database 2 Tworzenie obiektów SqlConnection i SqlDataAdapter Wypełnienie DataSet z DataAdapter i zamknięcie połączenia 3 Web server SqlConnection Zwraca DataSet do klienta 4 SqlDataAdapter 5 Zmiana danych przez użytkownika 6 Aktualizacja danych DataSet Użycie SqlDataAdapter do otwarcia połączenia SqlConnection, aktualizacja danych w bazie i zamknięcie połączenia 7 DataSet Rozłączony. By wypełnić obiekt DataSet danymi z bazy danych, trzeba najpierw utworzyć obiekt DataAdapter dla dostawcy danych (na przykład SqlDataAdapter) i połączyć go z obiektem SqlConnection. Obiekt SqlDataAdapter pośredniczy w procesie pobierania danych, wysyłając polecenia SqlCommand do bazy danych poprzez obiekt SqlConnection, odczytując dane i wypełniając obiekt DataSet. Client makes request 2. Create the SqlConnection and SqlDataAdapter objects Fill the DataSet from the DataAdapter and close the connection Return the DataSet to the Client Client manipulates the data Update the DataSet Use the SqlDataAdapter to open the SqlConnection, update the database, and close the connection List-Bound Control Client
Czym jest DataSet? DataSet – baza danych utrzymywana w pamięci(struktuwa relacyjna) DataSet zawiera wiele DataTables Relacje są reprezentowane poprzez DataRelation Można wymusić Constrainst Dostęp do danych w tabelach poprzez DataRow i DataColumn Tables DataTable DataView DataRow(s) DataColumn Constraint(s) Relations DataRelation DataViewManager DataTable DataTable DataColumn What Is a DataSet? Obiekt DataSet jest głównym obiektem przechowującym dane w odłączonej architekturze ADO.NET Obiekt DataSet może także odczytać i załadować swoją zawartość z dokumentu XML, a także wyeksportować zbiór rekordów do pliku XML. Ponieważ obiekt DataSet może być reprezentowany w formacie XML, można go łatwo przekazywać pomiędzy procesami, poprzez sieć lub przez Internet za pośrednictwem protokołu HTTP. W przeciwieństwie do obiektu DataReader, obiekt DataSet nie służy wyłącznie do odczytu danych. DataRow DataTable DataRelation
Stosowanie obiektu DataSet gdy dane muszą być edytowane lub gdy do bazy trzeba dodawać i usuwać rekordy. gdy zachodzi potrzeba organizowania danych - filtrowania, sortowania czy wyszukiwania gdy rekordy pobrane z bazy danych będą przetwarzane w wielu iteracjach gdy wynikowy zbiór danych pomiędzy kolejnymi odwołaniami do tej samej strony musi zostać zachowany w obiekcie Session lub Cache. do przekazywania wyników działania obiektów warstwy biznesowej i usług Web Service odłączony obiekt DataSet może być serializowany do postaci XML i przesyłany z wykorzystaniem protokołu HTTP Obiekt DataReader nie może być serializowany i dlatego nie może być przekazywany przez fizyczne granice pomiędzy warstwami aplikacji, przez które można przekazywać wyłącznie ciągi znaków (np. XML). Obiekty DataSet są również dobrym wyborem, gdy dane muszą być edytowane lub gdy do bazy trzeba dodawać i usuwać rekordy. W takiej sytuacji DataSet nie jest jedynym wyborem — do wczytania danych można zastosować obiekt DataReader, a zmiany mogą być zapisywane w bazie z wykorzystaniem obiektu SqlDataAdapter i oddzielnej, ręcznie budowanej tablicy DataRow Gdy jest potrzeba organizowania danych — filtrowania, sortowania czy wyszukiwania. Ponieważ obiekt DataSet pozwala na przechodzenie przez jego zawartość w dowolnym kierunku, dostępne są wszystkie wymienione opcje organizowania danych. Dzięki tej elastyczności obiekt DataSet jest również dobrym wyborem, gdy rekordy pobrane z bazy danych będą przetwarzane w wielu iteracjach. Obiekt DataReader pozwala tylko na jednokierunkowy odczyt danych, aby więc przetworzyć dane więcej niż jeden raz, należałoby go zamknąć i na nowo otworzyć, co wiązałoby się z ponownym wykonaniem zapytania. Jeśli zbiór wierszy wynikowych ma zostać związany z pojedynczą kontrolką serwerową ASP.NET, a dane przeznaczone są wyłącznie do odczytu, wystarczy zastosować obiekt DataReader. Jeśli z danych będzie korzystała więcej niż jedna kontrolka serwerowa ASP.NET, należy rozważyć użycie obiektu DataSet. Jeśli obiekt DataReader zostałby związany z więcej niż jedną kontrolką (na przykład z trzema kontrolkami DropDownList), to do bazy danych skierowane zostałyby trzy identyczne zapytania, ponieważ obiekt DataReader można odczytywać tylko w jednym kierunku Obiekt DataSet dobrze się sprawdza także w sytuacjach, gdy wynikowy zbiór danych pomiędzy kolejnymi odwołaniami do tej samej strony musi zostać zachowany w obiekcie Session lub Cache. Oczywiście — ponieważ obiekt DataReader jest powiązany z konkretnym źródłem danych — nie może być tworzony, wypełniany i przetwarzany bez połączenia z tym źródłem. W odróżnieniu od obiektu DataReader, obiekt DataSet może zostać utworzony ręcznie bez połączenia ze źródłem danych. Taki sposób działania jest przydany w rozwiązaniach typu koszyk w sklepie internetowym — obiekt DataSet może być ręcznie utworzony i ręcznie wypełniany rekordami. Obiekt DataSet jest też dobrym wyborem w sytuacji, w której na każdym rekordzie pobranych danych trzeba przeprowadzić skomplikowaną operację. .
DataSet vs. DataReader DataSet DataReader Operacje odczytu i zapisu Tylko do odczytu Wiele tabel z różnych źródeł Oparty o jedno polecenie SQL Bezpołączeniowy Połączeniowy Źródło dla wielu kontrolek Źródło dla jednej kontrolki Przesuwanie się w przód i tył Przesuwanie tylko do przodu Wolniejszy dostęp Szybszy dostęp Wspierany przez narzędzia automatyzujące pracę Wymaga ręcznej implementacji Obiekt DataReader jest lepszy: Gdy wymagane jest wypełnianie list lub odczytywanie 10.000 rekordów wykorzystywanych przez regułę biznesową. Gdy jakiś proces biznesowy musi mieć dostęp do ogromnej ilość danych, to nawet załadowanie obiektu DataSet, znajdującego się w środkowej warstwie aplikacji, wypełnienie go danymi z bazy danych w warstwie biznesowej i zapisanie go w pamięci może zająć dość dużo czasu. Może to mieć duży wpływ na wydajność aplikacji, a jeśli jednocześnie działa kilka instancji obiektu (na przykład w usłudze Web Service obsługującej setki użytkowników), skalowanie aplikacji mogłoby być sporym problemem. Jeśli dane mają zostać tylko wczytane na potrzeby przetwarzania jakiejś reguły biznesowej, zastosowanie obiektu DataReader może przyspieszyć cały proces — gdy dane odczytywane są wiersz po wierszu, nie są potrzebne tak duże zasoby pamięci jak w przypadku obiektu DataSet. Gdy aplikacja .NET nie stosująca powiązań danych (data bindings) — baza danych jest aktualizowana ręcznie, a kontrolki tworzone są w pętli przechodzącej przez wszystkie rekordy. Gdy aplikacja musi dostosowywać się do zmian w bazie danych, lepszym wyborem jest zastosowanie obiektu DataReader. Gdy konieczne jest odczytanie wyników lub parametrów wyjściowych, obiekt DataReader nie pozwoli na ich odczytanie zanim nie zostanie zamknięty wraz ze swoim połączeniem z bazą danych. Jeśli dane mają być wpisane do listy tylko do odczytu, znajdującej się w formularzu Web Form, obiekt DataReader jest bardzo dobrym wyborem. Dobrze działa także wiązanie obiektu DataReader z obiektem DropDownList w aplikacji ASP.NET lub obiektem DataGrid, przeznaczonym wyłącznie do odczytu danych, gdyż dane mogą zostać odczytane i wyświetlone na liście, ale nie muszą być przechowywane w celu ich edycji. Obiekt DataSet jest idealny, jeśli dane muszą być edytowane, sortowane, filtrowane lub przeszukiwane
Diagram klasy DataSet DataSet Class Diagram
Klasa DataSet DataSet składa się z DataTable składa się z DataRelation Kolecji DataTable Kolekcji DataRelation DataTable składa się z collection of DataTableColumns (= schema definition) collection of DataTableRows (= data) DefaultView (DataTableView) DataRelation Łączy dwa obiekty DataTable definiujue ParentTable i ParentColumns oraz ChildTable i ChildColumns Dostęp do: DataTable DataSet.Tables[0] DataSet.Tables[“tablename”] DataColumn DataTable.Columns[0] DataTable.Columns[“columnname”] DataRow DataTable.Rows[0] Pola tabeli DataRow[0] DataRow[“columnname”] DataRow[DataColumn] by DataColumn ? CreateDataSource zwraca DataSet DataSet has a DataSetName and Has a Collection of DataTables called Tables To access an individual DataTable use DataSet.Tables[0] by index DataSet.Tables[“tablename”] by table name DataTable has a TableName and Has a Collection of DataColumns called Columns To access an individual DataColumn use DataTable.Columns[0] by index DataTable.Columns[“columnname”] by columnname Has a Collection of DataRows called Rows To access an individual DataRow use DataTable.Rows[0] by index DataRow To access an individual field as object use DataRow[0] by index DataRow[“columnname”] by column name DataRow[DataColumn] by DataColumn
Typowany i nietypowany DataSet Typowany dataset jest datasetem, który dziedziczony jest z bazowej klasy DataSet, a następnie na podstawie informacji z bazy danych generuje nową klasę. Informacje o typach (tabele, kolumny, relacje, …) są dołączane do obiektu. VS daje możliwość automatyczniej generacji typowanych datasetów Może zostać zbudowany w oparciu o dane z pliku XSD Mniej podatne na błędy Mniejsza elastyczność Nietypowany dataset nie posiada wbudowanego schematu. Zawiera również tabele, wiersze, kolumny, jednak są one udostępniane jako zwykłe kolekcje Rozwiązanie bardziej elastyczne, umożliwia pracę z nieznannym źródłem Porównanie: Poprawne dla obu typów: MyDataSet.Tables[“News”].Rows[0][“Title”] Poprawne tylko dla typowanego DataSet + zwraca dane we właściwym formacie MyDataSet.News[0].Title Typed DataSets provide typed data access Tool xsd.exe generates classes from XML schema Classes define properties for typed access to rows, columns, and relations Data access in conventional DataSet DataSet ds = new DataSet("PersonContacts"); DataTable personTable = new DataTable("Person"); ... ds.Tables.Add(personTable); DataRow person = personTable.NewRow(); personTable.Rows.Add(person); person["Name"] = "Beer"; person.GetChildRows("PersonHasContacts")[0]["Name"] = "Beer"; Data access in typed DataSet PersonContacts typedDS = new PersonContacts(); PersonTable personTable = typedDS.Person; Person person = personTable.NewPersonRow(); personTable.AddPersonRow(person); person.Name = "Beer"; person.GetContactRows()[0].Name = "Beer";
Zdarzenia w DataTable Podział na trzy kategorie: Dla kolumn: ColumnChanging, ColumnChanged DataColumnChangeEventsArgs: Column, ProposedValue, Row Dla wierszy: RowChanging, RowChanged, RowDeleting, RowDeleted DataRowChangeEventArgs: Action (Add, Change, ChangeCurrentAndOriginal, ChangeOriginal, Commit, Delete, Nothing, Rollback), Row Dla tabel: TableClearing, TableCleared, TableNewRow DataTableClearEventArgs: Table, TableName, TableNamespace DataTableNewRowEventArgs key member: Row
Wypełnianie DataSet: DataAdapter DataAdapter służy jako most pomiędzy DataSetem a źródłem danych pozwalający na wymianę danych. DataAdapter reprezentuje zestaw poleceń oraz połączenie bazodanowe które są uzywane do wypełnia DataSet oraz aktualizacji bazy. Dane są wymieniane poprzez zapytania SQL lub procedury składowane. DataAdapter - właściwości: SelectCommand – odczytuje dane ze źródła InsertCommand – zapisuje dane z DataSet do bazy UpdateCommand – aktualizuje dane w bazie danymi z DataSet DeleteCommand – usuwa dane z DataSer DataAdapter – metody: Fill – odświeża DataSet danymi z bazy (używa SELECT) Update – przenosi zmiany z DataSet do bazy (używa INSERT, UPDATE, DELETE) TableMappings: mapping from table data base table to DataSet tablePodajnik danych – data provider, Przetwornik danych – DataAdapter, Czytnik danych -DataReader Obiekt SqlDataAdapter można uważać za pomost pomiędzy obiektami połączonymi a odłączonymi. Jednym z jego zadań jest zapewnienie możliwości przesłania do obiektu DataSet zbioru wierszy, będących wynikiem wykonania polecenia. Na przykład wykonanie metody Fill obiektu SqlDataAdapter powoduje otwarcie powiązanego z tą metodą obiektu SqlConnection (jeśli nie jest on jeszcze otwarty) i przesłanie przez ten obiekt zapytania, zapisanego w obiekcie SqlCommand, przypisanym do tej metody. Metoda ta niejawnie tworzy obiekt SqlDataReader, pobiera z bazy danych zestaw rekordów i kolejno wypełnia nimi obiekt DataSet. Gdy już wszystkie dane znajdą się w obiekcie DataSet, obiekt SqlDataReader zostaje zniszczony, a obiekt SqlConnection — zamknięty.
DataAdapter - polecenia Tworzone w trzy sposoby Użycie obiektu CommandBuilder by stworzyć Command podczas wykonania Proste do realizacji, narzut na wykonanie Ograniczenie do Select dla jednej tabeli Poprzez Visual Studio w trakcie tworzenia aplikacji Proste do realizacji, brak narzutu na wykonanie Stworzenie programowo podczas tworzenia aplikacji Wysoka kontrola i wydajność Brak ograniczeń Narzut na czas implementacji
CommandBuilder Obiekt CommandBuilder generuje polecenia wymagane do aktualizacji źródła danych po wprowadzeniu zmian w obiekcie DataSet. Ograniczenia: polecenie Select dotyczy pojedynczej tabeli tabela w bazie musi mieć klucz główny lub unikatową kolumnę zawartą w oryginalnym poleceniu Select DataTable dt= ds.Tables["movies"]; // Use command builder to generate update commands SqlCommandBuilder sb = new SqlCommandBuilder(da); // Add movie to table DataRow drow = dt.NewRow(); drow["movie_Title"] = "Taxi Driver"; drow["movie_Year"] = "1976"; dt.Rows.Add(drow); // Delete row from table dt.Rows[4].Delete(); // Edit Column value dt.Rows[5]["movie_Year"] = "1944"; // Update underlying Sql Server table int updates = da.Update(ds, "movies"); MessageBox.Show("Rows Changed: " +updates.ToString()); ??? Sb The SqlDataAdapter does not automatically generate the Transact-SQL statements required to reconcile changes made to a DataSet with the associated instance of SQL Server. However, you can create a SqlCommandBuilder object to automatically generate Transact-SQL statements for single-table updates if you set the SelectCommand property of the SqlDataAdapter. Then, any additional Transact-SQL statements that you do not set are generated by the SqlCommandBuilder. The SqlCommandBuilder registers itself as a listener for RowUpdating events whenever you set the DataAdapter property. You can only associate one SqlDataAdapter or SqlCommandBuilder object with each other at one time. To generate INSERT, UPDATE, or DELETE statements, the SqlCommandBuilder uses the SelectCommand property to retrieve a required set of metadata automatically. If you change the SelectCommand after the metadata has been retrieved, such as after the first update, you should call the RefreshSchema method to update the metadata.
Data Adapter - tworzenie Zapisanie zapytania w DataAdapter Konstruktor ustawia wartość SelectCommand Gdy wymagane, utworzenie InsertCommand, UpdateCommand, DeleteCommand SqlDataAdapter da = new SqlDataAdapter ("select * from Authors",conn); da.SelectCommand.CommandText; da.SelectCommand.Connection; Visual C#: Creating a Data Adapter Programmatically using System.Data.SqlClient; … SqlDataAdapter daProducts = new SqlDataAdapter(); SqlConnection cnNorthwind = new SqlConnection( "data source=(local);initial catalog=Northwind;" + "integrated security=SSPI"); SqlCommand cmSelect = new SqlCommand( "SELECT * FROM Products", cnNorthwind); daProducts.SelectCommand = cmSelect;
DataSet - tworzenie Ładowanie danych poprzez SelectCommand obiektu DataAdapter Definicja SQL, przez który zostaną załadowane dane SelectCommand jako konstruktor private void Demo() { SqlDataAdapter da = new SqlDataAdapter( "SELECT City FROM Authors", "Server=localhost; Database=Pubs; Integrated Security=SSPI" ); DataSet ds = new DataSet(); da.Fill( ds, "Authors" ); // Opens and closes a connection foreach ( DataRow dr in ds.Tables[ "Authors" ].Rows ) Console.WriteLine( dr[ "City" ] ); // Writes list of cities }
DataSet - tworzenie Tworzenie i załadowanie danymi DataTable Fill wywołuje SelectCommand obiektu DataAdapter Dostęp do DataTable DataSet ds = new DataSet(); da.Fill(ds, "Authors"); ds.Tables["Authors"].Rows.Count; string str=""; foreach(DataRow r in ds.Tables["Authors"].Rows) { str += r[2]; str += r["au_lname"]; } Creating a DataSet: Drag and drop a DataSet control from the Toolbox. Creating a DataTable: Edit the Tables collection of a DataSet by using the Properties window. Creating a DataColumn and adding it to a DataTable: Edit the Columns collection of a DataTable by using the Properties window How to Create a Primary Key Constraint: Set the PrimaryKey property of the DataTable: Select the columns in order,Does not allow the naming of the constraint Edit the Constraints collection of the DataTable: Add a UniqueConstraint, Name the constraint, Select the columns, Check the primary key box, Using Unique Constraints Two types of constraints: UniqueConstraint, ForeignKeyConstraint Creating a constraint: Edit the Constraints collection of a DataTable UniqueConstraint: Array of DataColumns, Can be the primary key for the DataTable Custom expressions are columns derived from calculations, rather than stored values Using the DataColumn Expression property: Sum([Unit Price] * [Quantity]) Aggregate functions can use parent/child relationships: Avg, Count, Sum, Max, Min Obiekt DataSet może odczytać i załadować swoją zawartość z dokumentu XML, a także wyeksportować zbiór rekordów do pliku XML. Ponieważ obiekt DataSet może być reprezentowany w formacie XML, można go łatwo przekazywać pomiędzy procesami, poprzez sieć lub przez Internet za pośrednictwem protokołu HTTP. W przeciwieństwie do obiektu DataReader, obiekt DataSet nie służy wyłącznie do odczytu danych. Obiekt DataSet może być wczytany nie tylko z XML — jego zawartość może być wpisana ręcznie. Na ilustracji 2 pokazano proces tworzenia obiektu DataTable — ręczne utworzenie kolumn , definicja klucza podstawowego i ustawienie autoinkrementacji wartości tego klucza. Następnie obiekt DataTable zostaje dopisany do pustego obiektu DataSet (chociaż obiekt ten nie musi być pusty). Na koniec do obiektu DataTable kolejno dopisywane są wiersze. Wszystkie te operacje odbywają się bez łączenia ze źródłem danych.
Wypełnianie DataSet Wydajność Zdefiniowanie schematu przed wypełnieniem DataSet DataTables, DataColumns, DataRelations są znane przed załadowaniem danych Zwiększenie wydajności Tworzenie typowanych DataSet: dsCustomers.Customers.BeginLoadData(); daCustomers.Fill(dsCustomers.Customers); dsCustomers.Customers.EndLoadData(); dataGrid1.DataSource = dsCustomers.Customers.DefaultView;; Dane z wielu DataAdapter DataSet może przechowywać dane z wielu obiektów DataAdapter 1 DataAdapter = 1 DataTable Wywołanie metody Fill Określenie tabeli daCustomers.Fill(dsCustomerOrders.Customers); daOrders.Fill(dsCustomerOrders.Orders); dataGrid1.DataSource = dsCustomerOrders.Customers.DefaultView; Visual C#: Defining a DataSet Schema Programmatically // Create the DataTable and DataColumns DataTable table = new DataTable("Customers"); DataColumn c1 = new DataColumn("CustomerID", typeof(String)); DataColumn c2 = new DataColumn("CompanyName", typeof(String)); DataColumn c3 = new DataColumn("ContactName", typeof(String)); // Add DataColumns and Constraints to the DataTable table.Columns.Add(c1); table.Columns.Add(c2); table.Columns.Add(c3); table.Constraints.Add("PK_CustomerID", c1, true); // Create the DataSet, and add the DataTable to it DataSet dsCustomers = new DataSet(); dsCustomers.Tables.Add(table); // Fill DataSet by using a DataAdapter, and bind to a DataGrid dsCustomers.Tables[0].BeginLoadData(); daCustomers.Fill(dsCustomers, "Customers"); dsCustomers.Tables[0].EndLoadData(); dataGrid1.DataSource = dsCustomers.Tables[0].DefaultView; You can use multiple DataAdapters to fill a DataSet. Each DataAdapter fills a separate table in the DataSet. Because each DataAdapter maps to a single DataSet table, you can control the order in which updates are written back to the database. This helps you to preserve referential integrity between related tables in the database.
DataSet - podsumowanie DataSet może: Przechowywać dane w wielu powiązanych tabelach Modelować zależności między tabelami Zarządza constrainami Daje dostęp do widoków celem bardziej efektywnego wyświetlania danych Być przesyłany pomiędzy procesami i warstwami DataSet i XML: XML może zostać załadowany do DataSet DataSet może zostać przesłany jako XML DataSet może wczytywać xsd
DataView DataView służy modyfikowaniu DataTable celem wyświetlenia potrzebych danych DefaultView zwraca standardowy widok dla DataTable Modyfikacja widoku z DataSet poprzez filtry DataView dv = ds.Tables["Authors"].DefaultView; DataView dv = new DataView(ds.Tables["Authors"]); dv.RowFilter = "state = 'CA'"; Trzy parametry opcjonalne Filter, "City='London'" Sort, "CompanyName ASC" DataViewRowState Obiekt domyślnego, nieprzefiltrowanego i nieposortowanego widoku z obiektu DataTable można uzyskać za pośrednictwem właściwości DefaultView. Zawarte w DataSet obiekty typu DataTable mogą być w dowolny sposób filtrowane i sortowane oraz przeszukiwane. Creating a DataView by using form controls Creating a DataView programmatically DataViews allow sorting and filtering at design time A DataView cannot span multiple DataTables, unlike the View object in SQL Server Use presentation-level objects instead (for example, the DataGrid control, report designers, and so on) Every DataTable has a DefaultView property
Relacje Kolumna rodzica Kolumna dziecka Stworzenie relacji DataSet DataColumn parentCol = ds.Tables["Customers"].Columns["CustomerID"] childCol = ds.Tables["Orders"].Columns["CustomerID"] parentCol DataRelation Customers table dr = New DataRelation _ („CustOrders", parentCol, _ childCol) ds.DataRelations.Add(dr) Użytkownik wybiera rekord i wyświetla dane szczegółowe związane z tym rekordem. DataRelation myDataRelation; DataColumn parentColumn; DataColumn childColumn; W ramach DataSet możemy definiować związki pomiędzy elementami w DataTable Definiując relacje można wybierać powiązane rekordy wg. zasady rodzic/potomek Jak za dużo – zwalnia True – tworzy także więzy Więzy muszą być spełnione Used by presentation objects (for example, a DataGrid) to allow easier navigation (for example, “drill down” capability from parent rows to child rows) Used by expression columns to calculate aggregates A DataSet has a Relations collection Visual C#: How to Create a Foreign Key Constraint dtCustomers = dsNorthwind.Tables["Customers"]; dtOrders = dsNorthwind.Tables["Orders"]; ForeignKeyConstraint fkcCustomersOrders = new ForeignKeyConstraint("FK_CustomersOrders", dtCustomers.Columns["CustomerID"], dtOrders.Columns["CustomerID"]); fkcCustomersOrders.DeleteRule = Rule.None; dtOrders.Constraints.Add(fkcCustomersOrders); childCol DataSet Orders table DataRelation definiuje relację na potrzeby nawigacji
Nawigacja poprzez relacje ds.Tables[index].Rows[index].GetChildRows("relation"); ds.Tables[index].Rows[index].GetParentRow("relation"); Customers Orders GetChildRows GetParentRow DataSet DataView tableView; DataRowView currentRowView; tableView = new DataView(ds.Tables["Customers"]); currentRowView = tableView[dgCustomers.SelectedIndex]; dgChild.DataSource = currentRowView.CreateChildView("CustOrders"); Pass a DataRelation name as the parameter Customers Orders CreateChildView DataRowView DataView DataSet
Modyfikacja danych w DataTable BeginEdit rozpoczyna edycję danych EndEdit i CancelEdit kończą edycję danych DataRos drEmployee = dtEmployees.Rows(3) drEmployee.BeginEdit() drEmployee("FirstName") = "John" drEmployee("LastName") = "Smith" drEmployee.EndEdit() Wstawianie wiersza Stworzenie wiersza DataRow drNewEmployee = dtEmployees.NewRow() Wypełnienie danymi drNewEmployee("EmployeeID") = 11 drNewEmployee("LastName") = "Smith" Dodanie do DataTable dtEmployees.Rows.Add(drNewEmployee) Jednowierszowo dtEmployees.Rows.Add( New Object() {11, "Smith"}) Zawartość obiektu DataSet może być modyfikowana, można także dodawać lub kasować wiersze. Zmiany wprowadzone w obiekcie DataSet mogą zostać ponownie zapisane w bazie danych z wykorzystaniem obiektów zarządzanego dostawcy danych. What Are the RowState and RowVersion Properties? RowState property of a DataRow Added, Deleted, Detached, Modified, Unchanged DataViewRowState enumeration Used with a DataView to filter rows of a certain state CurrentRows, OriginalRows, and so on DataRowVersion enumeration is used when retrieving values using the Item property Current, Default, Original, Proposed HasVersion method of a DataRow AcceptChanges and RejectChanges methods Do aktualizacji źródła danych można użyć pojedynczej instrukcji SQL. Innym rozwiązaniem jest przeprowadzenie zmiany w pamięci a następnie przeprowadzenie aktualizacji wsadowej. Wszystko zależy od …Command Porównanie wszystkich wartości Timestamp Wcale?
Modyfikacja danych w DataTable Usuwanie wiersza Metoda Remove Usuwa wiersz z kolekcji Przykład: dtEmployees.Rows.Remove(drEmployee) Metoda Delete klasy DataRow Oznacza wiersz jako usunięty Wiersz staje się „ukryty”, możemy uzyskać do niego dostęp drEmployee.Delete() To add a new row to a table call the Add method of the table’s Rows property The table’s NewRow method creates a new row, but does not add it to the table To delete a row call the row’s Delete method Delete sets the row’s state to Deleted, but does not remove it from the table To remove a row from a table call Remove method of the table’s Rows property Removed rows are not processed by DataAdapter updates so Remove should be used with care
Śledzenie zmian w DataSet DataRow może przechowywać wiele wersji wiersza: DataRowVersion.Current Aktualna wartość DataRowVersion.Original Wartość przed dokonaniem zmian DataRowVersion.Proposed Wartość w trakcie cyklu BeginEdit / EndEdit DataRowVersion.Default Wartość standardowa
RowVersion - stany CURRENT ORIGINAL PROPOSED White White N/A White White Brown Brown White N/A dataRow.BeginEdit(); dataRow[ "au_lname" ] = "Brown"; dataRow.EndEdit(); dataRow[ "au_lname", DataRowVersion.Current ] // Brown dataRow[ "au_lname", DataRowVersion.Original ] // White
Diagram stanów obiektu DataRow DataRow może być w różnych stanach public DataRowState RowState {get;} public enum DataRowState { Added, Deleted, Detached, Modified, Unchanged } State Diagram of a DataRow object
Modyfikacja źródła danych Modyfikacja źródła danych przez DataAdapter InsertCommand, UpdateCommand, DeleteCommand Modyfikacje są zapisywane poprzez metodę Update obiektu DataAdapter DataAdapter przeszukuje wiersze pod kątem RowState Wykonuje akcję zgodnie ze stanem wiersza DataRows in DataTable RowState = Modified Use UPDATE command RowState = Unchanged Ignore Creating the SQL commands that post the changes and assigning them to the appropriate DataAdapter properties A CommandBuilder object generates the commands necessary to update a data source with changes made to a DataSet. SqlCommandBuilder sb = new SqlCommandBuilder(aDataAdapter); Code example aDataAdapter.Update(aDataSet, aDataTable) Rozwiązywanie konfliktu: Porównanie wszystkich wartości.Timestamp. Ostatni ma rację. Syntax – essentially the same for both Sql and OleDb DataAdapters and for the series of command objects public SqlCommand InsertCommand {get; set;} Visual C#: Data Modification Commands // Using the InsertCommand property SqlCommand cmInsert = new SqlCommand( "INSERT INTO Customers VALUES (@ID, @Name)", cnNorthwind); cmInsert.Parameters.Add(new SqlParameter("@ID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Current, null)); cmInsert.Parameters.Add(new SqlParameter("@Name", SqlDbType.NVarChar, 40, ParameterDirection.Input, false, 0, 0, "CompanyName", DataRowVersion.Current, null)); daCustomers.InsertCommand = cmInsert; // Using the UpdateCommand property SqlCommand cmUpdate = new SqlCommand( "UPDATE Customers SET CustomerID = @ID, " + "CompanyName = @Name WHERE (CustomerID = @OrigID)",cnNorthwind); cmUpdate.Parameters.Add(new SqlParameter("@ID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Current, null)); cmUpdate.Parameters.Add(new SqlParameter("@Name", SqlDbType.NVarChar, 40, ParameterDirection.Input, false, 0, 0, "CompanyName", DataRowVersion.Current, null)); cmUpdate.Parameters.Add(new SqlParameter("@OrigID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Original, null)); daCustomers.UpdateCommand = cmUpdate; // Using the DeleteCommand SqlCommand cmDelete = new SqlCommand( "DELETE FROM Customers WHERE (CustomerID = @ID)",cnNorthwind); cmDelete.Parameters.Add(new SqlParameter("@ID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Original, null)); daCustomers.DeleteCommand = cmDelete; RowState = Added Use INSERT command RowState = Modified Use UPDATE command RowState = Deleted Use DELETE command
Optymalizacja zmian DataSet oraz DataTable wspierają metodę GetChanges GetChanges bez argumentów Pobiera wiersze, których RowState jest inny niż Unchanged Wykorzystanie podczas przekazywania między warstwami dsChanges = ds.GetChanges(); GetChanges z argumentem RowState Wiersze, które mają określony RowState Pozwala zarządzać kolejnością aktualizacji changes = ds.GetChanges( DataRowState.Added ); Medota Merge pozwala na scalenie danych
Obsługa współbieżnego dostępu do danych Tryb bezpołączeniowy używa podejścia optymistycznego (optimistic concurrency) Zwalnianie blokad podczas rozłączania Możliwość konfliktów Dane mogły zostać zmienione Usunięcie wiersza Zmiana wartości w polu wiersza Wykrywanie konfliktów Data Adapter Configuration Wizard pozwala generować zapytania SQL wykrywające konflikty Podczas aktualizacji: Porównanie bieżących wartości z oryginalnymi (where …) Różnice powodują konflikt Dodanie do tabeli pola timestamp - aktualizacja pola przy zmianie wartości. Podejście pesymistyczne opiera się na założeniu, że jeśli nie pozwolimy na dostęp do danych, z którymi aktualnie pracujemy, nikt nie będzie mógł spowodować konfliktu współbieżnego dostępu do danych. Taka taktyka — ze względu na uniemożliwienie współbieżnego dostępu do danych — charakteryzuje się ograniczoną skalowalnością. Przy blokowaniu pesymistycznym, rekord blokowany jest od chwili odczytania danych do chwili zapisania zmodyfikowanych danych do bazy. Metoda ta wymaga utrzymania otwartego połączenia ze źródłem danych podczas całego procesu edycji — dlatego w modelu odłączonym, zastosowanym w ADO.NET, gdy połączenie utrzymywane jest tylko na czas wypełniania obiektu DataSet danymi, blokowanie pesymistyczne nie może zostać zastosowane. Inną metodą rozwiązywania problemów związanych ze współbieżnością jest prosta i łatwa w implementacji technika ostatni wygrywa. Technika ta jest niezwykle prosta — niezależnie od tego, jakie zmiany zostały wprowadzone w bazie danych, zapisana zostanie tylko ostatnia modyfikacja. Zastosowanie tej metody polega na umieszczeniu w klauzuli WHERE polecenia UPDATE wyłącznie klucza podstawowego. W metodzie ostatni wygrywa konflikty współbieżności nie są wykrywane, więc użytkownicy nie mogą zostać o nich poinformowani. Wykrywanie konfliktów zapewniane jest natomiast przez metodę optymistyczną. Przy optymistycznym blokowaniu rekordów, wiersz jest blokowany tylko w czasie uaktualniania bazy danych. Oznacza to, że dane nie mogą zostać odczytane oraz zaktualizowane przez użytkownika tylko wtedy, gdy rekord ten jest właśnie aktualizowany przez innego użytkownika. Blokowanie optymistyczne pozwala na równoczesny odczyt danych przez wielu użytkowników, dostęp blokowany jest rzadziej niż w przypadku blokowania pesymistycznego. Dzięki temu jest to dobry wybór dla ADO.NET. W modelach optymistycznych ważne jest, by zaimplementować mechanizm wykrywania konfliktów współbieżnego dostępu do danych, wychwytujący próby równoczesnej modyfikacji rekordów przez wielu użytkowników. By obsłużyć taki konflikt, można napisać własny kod, który na podstawie określonych reguł biznesowych będzie odrzucał i anulował próby dokonania zmian lub nadpisywał istniejące dane. Innym sposobem jest pozostawienie decyzji użytkownikowi. http://msdn.microsoft.com/en-us/library/aa0416cz.aspx http://msdn.microsoft.com/msdnmag/issues/04/09/DataPoints
Naruszenie spójności danych User1 czyta wiersz Column name Original value Current value Value in database CustID 101 LastName Smith FirstName Bob User2 zmienia FirstName z "Bob" na "Robert" i zapisuje zmiany Column name Original value Current value Value in database CustID 101 LastName Smith FirstName Bob Robert User1 zmienia FirstName na "James”i próbuje aktualizować bazę 1. A timestamp column is included in the table definition; whenever the record is updated, the timestamp is updated to reflect the current date and time. In a test for optimistic concurrency violations, the timestamp column is returned with any query of the contents of the table. When an update is attempted, the timestamp value in the database is compared to the original timestamp value contained in the modified row. If they match, the update is performed and the timestamp column is updated with the current time to reflect the update. If they do not match, an optimistic concurrency violation has occurred. 2. Verify that all the original column values in a row still match those found in the database. UPDATE Table1 Set Col1 = @NewCol1Value, Set Col2 = @NewCol2Value, Set Col3 = @NewCol3Value WHERE Col1 = @OldCol1Value AND Col2 = @OldCol2Value AND Col3 = @OldCol3Value As long as the original values match the values in the database, the update is performed. If a value has been modified, the update will not modify the row because the WHERE clause will not find a match. It is recommended to always return a unique primary key value in your query The DataAdapter.RowUpdated Event The RowUpdated event of the DataAdapter object can be used in conjunction with the techniques described earlier, to provide notification to your application of optimistic concurrency violations. RowUpdated occurs after each attempt to update a Modified row from a DataSet. This enables you to add special handling code, including processing when an exception occurs, adding custom error information, adding retry logic, and so on. The RowUpdatedEventArgs object returns a RecordsAffected property containing the number of rows affected by a particular update command for a modified row in a table. By setting the update command to test for optimistic concurrency, the RecordsAffected property will, as a result, return a value of 0 when an optimistic concurrency violation has occurred, because no records were updated. If this is the case, an exception is thrown. The RowUpdated event enables you to handle this occurrence and avoid the exception by setting an appropriate RowUpdatedEventArgs.Status value, such as UpdateStatus.SkipCurrentRow. For more information about the RowUpdated event, see Handling DataAdapter Events (ADO.NET). Zdarzenie RowUpdated DataAdaptera występuje przy każdej próbie zapisu wiersza z DataSet oznaczonego w nim jako zmodyfikowanego (Modified). W tym miejscu zasadne jest umieszczenie kodu obsługi powiadamiającego o błędzie, obsługi tej sytuacji wyjątkowej. Obiekt RowUpdateEventArgs we właściwości RecordsAffected zwraca ilość wierszy, na których dokonano modyfikacji przy wołaniu Update. W przypadku konfliktu zwracana jest wartość 0 i generowany jest wyjątek. Możliwe jest ustawienia dla RowUpdatedEventArgs.Status wartości z trybu wyliczeniowego UpdateStatus np. UpdateStats.SkipCurrentRow. Optionally, you can set DataAdapter.ContinueUpdateOnError to true, before calling Update, and respond to the error information stored in the RowError property of a particular row when the Update is completed. For more information, see Handling DataRow and DataColumn Errors (ADO.NET). Do wykrycia rozbieżności można wykorzystać właściwość adaptera DataAdapter.ContinueUpdateOnError i ustawić ją na true przed wywołaniem metody Update na tym adapterze. Pozwoli to na kontynuowanie prób zapisu kolejnych wierszy w przypadku wystąpienia kolizji przy zapisie danego wiersza. Dla wiersza kolizyjnego zostanie w jego właściwości RowError umieszczona informacja o błędzie. Po pełnym udanym Update wszystkich wierszy w tabeli powinna ona nie mieć wpisanych zmian (hasChanges). Jeżeli są zmiany to dane elementy nie zostały prawidłowo zapisane i należy podjąć decyzję co z nimi zrobić. Odrzucenie proponowanych zmian następuje przez RejectChanges dla wiersza lub całej tabeli. Column name Original value Current value Value in database CustID 101 LastName Smith FirstName Bob James Robert
Wykrywanie konfliktów // Visual C#: How the Data Adapter Configuration Wizard Supports Optimistic Concurrency this.cmUpdate.CommandText = "UPDATE Customers " + "SET CustomerID=@CustomerID, CompanyName=@CompanyName " + " WHERE (CustomerID = @Original_CustomerID) " + " AND (CompanyName = @Original_CompanyName); " + "SELECT CustomerID, CompanyName FROM Customers " + " WHERE (CustomerID = @CustomerID)"; this.cmUpdate.Parameters.Add(new SqlParameter( "@CustomerID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Current, null)); this.cmUpdate.Parameters.Add(new SqlParameter( "@CompanyName", SqlDbType.NVarChar, 40, ParameterDirection.Input, false, 0, 0, "CompanyName", DataRowVersion.Current, null)); this.cmUpdate.Parameters.Add(new SqlParameter( "@Original_CustomerID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0 , "CustomerID", DataRowVersion.Original, null)); this.cmUpdate.Parameters.Add(new SqlParameter( "@Original_CompanyName", SqlDbType.NVarChar, 40, ParameterDirection.Input, false, 0, 0, "CompanyName", DataRowVersion.Original, null)); this.cmUpdate.Parameters.Add(new SqlParameter( "@CustomerID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Current, null)); Data conflicts happens if the data source has been changed by another application or service while your application was disconnected from the data source. The wizard adds SQL tests to the InsertCommand, UpdateCommand, and DeleteCommand. These tests check to see if the data in the database has not been changed since you retrieved it into your application. Visual C#: How the Data Adapter Configuration Wizard Supports Optimistic Concurrency
Rozwiązywanie konfliktów Właściwość HasErrors Sprawdza DataSet, DataTable, DataRow Jedna ze strategii: “Last in wins” – zmiany są zapisywane niezależnie od stanu Zatrzymanie wartości w DataSet i aktualizacja później Odrzut konfliktów i wypełnienie ich danymi z DataSet Odrzut konfliktów i wypełnienie ich danymi z bazy The DataRow class also has a GetColumnsInError method to get the columns in error for a particular row. After an Update operation, the HasErrors property is tested to see if the DataSet has any errors. If there are errors, a loop is used to check each table in turn. If a table has errors, another loop is used to check each of its rows. If a row has errors, the GetColumnsInError method is used to find the columns in error. The ClearErrors and RejectChanges methods are then called to clear the error status and reject the conflicting data in each row Visual C#: Resolving Conflicts in a Disconnected Environment // Visual C# try { daCustomers.Update(dsCustomers); } catch(System.Exception ex) if(dsCustomers.HasErrors) foreach(DataTable table in dsCustomers.Tables) if(table.HasErrors) foreach(DataRow row in table.Rows) if(row.HasErrors) MessageBox.Show("Row: " + row["CustomerID"], row.RowError); foreach(DataColumn col in row.GetColumnsInError()) MessageBox.Show(col.ColumnName, "Error in this column"); row.ClearErrors(); row.RejectChanges(); } } } } } }
Kontrolki źródła danych ObjectDataSource Umożliwia połączenie z obiektami logiki biznesowej i innych klas i służy do tworzenia aplikacji webowych które bazują na obiektach warstwy pośredniej do zarządzania danymi. Wspiera zaawansowane sortowania i dzielenie na strony niedostępne w innych kontrolkach źródeł danych. SqlDataSource Umożliwia połączenie do serwerów baz danych takich jak Microsoft SQL Server czy Oracle. We współpracy z serwerem SQL Server wspiera zaawansowane możliwości buforowania. Kontrolka wspiera również sortowanie, filtrowanie i dzielenie na strony, jeśli dane są zwracane jako obiekt DataSet. AccessDataSource Umożliwia współpracę z bazami danych zapisanymi w Microsoft Access. Kontrolka wspiera sortowanie, filtrowanie i dzielenie na strony, jeśli dane są zwracane jako obiekt DataSet XmlDataSource Umożliwia pobieranie danych zapisanych w plikach XML, szczególnie dla hierarchicznych kontrolek serwerowych ASP.NET takich jak TreeView. Wspiera filtrowanie przy użyciu wyrażeo XPath i umożliwia stosowanie transformacji danych przy użyciu XSLT. Umożliwia również aktualizację danych przez zapisanie całego dokumentu XML ze zmianami. SiteMapDataSource Używana w ASP.NET do nawigacji na stronie LinqDataSource Umożliwia użycie języka LINQ na stronach ASP.NET poprzez model deklaratywny do pobrania i modyfikowania danych z obiektów danych takich jak tabele w bazie czy kolekcje w pamięci serwera. Wspiera automatyczne generowanie poleceń wybierania, aktualizacji, dodawania i usuwania danych. Kontrolka wspiera sortowanie, filtrowanie i dzielenie na strony EntityDataSource Umożliwia połączenie z danymi pochodzącymi z modelu Entity Data Model (EDM). Wspiera automatyczne generowanie poleceń wybierania, aktualizacji, dodawania i usuwania danych. Kontrolka wspiera sortowanie, filtrowanie i dzielenie na strony.
Połączenie i tworzenie zapytań przy pomocy SqlDataSource Określić atrybuty kontrolki SqlDataSource: ConnectionString – łańcuch połączenia. ProviderName – nazwa dostawcy danych. SelectCommand – polecenie SQL zawierające treść zapytania do bazy danych lub nazwa procedury składowanej do wykonania. <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="Data Source=.\SQLEXPRESS; AttachDbFilename=|DataDirectory|\CDDB.mdf; Integrated Security=True; User Instance=True" ProviderName="System.Data.SqlClient" SelectCommand="SELECT * FROM [Kategorie]"> </asp:SqlDataSource> lub <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:PolaczenieDoBazy %>" SelectCommand="SELECT * FROM [Kategorie]"> </asp:SqlDataSource> W bloku <configuration> pliku Web.config <connectionStrings> <add name="PolaczenieDoBazy" connectionString="Data Source=.\SQLEXPRESS; AttachDbFilename=|DataDirectory|\CDDB.mdf;Integrated Security=True; User Instance=True" providerName="System.Data.SqlClient" /> </connectionStrings>
Połączenie i tworzenie zapytań przy pomocy SqlDataSource Konfiguracja treści zapytania do bazy <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:PolaczenieDoBazy %>" SelectCommand="SELECT * FROM [Kategorie]" DeleteCommand="DELETE FROM [Kategorie] WHERE [KatID] = @KatID" InsertCommand="INSERT INTO [Kategorie] ([Nazwa]) VALUES (@Nazwa)" UpdateCommand="UPDATE [Kategorie] SET [Nazwa] = @Nazwa WHERE [KatID] = @KatID"> <DeleteParameters> <asp:Parameter Name="KatID" Type="Int32" /> </DeleteParameters> <UpdateParameters> <asp:Parameter Name="Nazwa" Type="String" /> </UpdateParameters> <InsertParameters> </InsertParameters> </asp:SqlDataSource>
XML i Dataset Database XML File XML File DataSet Object WriteXML XML File XML File DataAdapter Doc.Save DataSet Object XmlDataDocument Object Database XslTransform Object ReadXML XML plays an important role in the way that data is handled in the .NET Framework. XML is the format that is used in the .NET Framework for storing and transmitting all kinds of data. DataSets are able to store and transmit data in XML format. Regarding DataSets and XML features: Structure of a DataSet can be defined in an XML Schema The structure of a DataSet that includes tables, columns, relationships, and constraints can be defined by using an XML Schema. XML Schemas are a standards-based format of the W3C that can be used for defining the structure of XML data. Generate a DataSet class You can generate a DataSet class that incorporates schema information to define its data structures (such as tables and columns) as class members. DataSet methods You can read an XML document or stream it into a DataSet by using the ReadXML method of the DataSet and then write a DataSet in XML by using the WriteXML method of the DataSet. Because XML is a standard interchange format for data between different Web applications, you can load a DataSet with XML-formatted information that was sent by other applications. Similarly, a DataSet can write out its data as an XML stream or document that will be shared with other applications or simply stored as an XML document Create an XML view of the contents of a DataSet You can create an XML view (an XmlDataDocument object) of the contents of a DataSet, and then view and manipulate the data by using either relational methods (by means of the DataSet) or XML methods. The two views are automatically synchronized as they are changed. Transformation of data You can use the XSLTransform object to load an .xsl style sheet file and apply the transformation. The resulting document can be an XML or HTML file. XML File XML or HTML File XSLT File
Dlaczego używać XML z Dataset XML to uniwersalny format wymiany danych między klientami Synchronizacja i transformacja danych Firewall Human Readable Web Server XML File Or Stream Browser Readable DataSet Mainframe Readable XML is a universal format that is used for exchanging data on the Internet and a DataSet is a relational view of data that can be represented in XML. XML is used with the DataSets in the following ways: Serialize data DataSets can serialize data as XML. The schema of a DataSet that includes tables, columns, data types, and constraints is defined by using an XML Schema (.xsd file). XML and XML Schema XML and XML Schemas provide a convenient format for transferring the contents of a DataSet to and from remote clients. You can infer XML Schemas from existing DataSets and create DataSets from existing XML Schemas. Synchronize and transform data You can use different XML objects to synchronize and transform data that is represented by DataSets Typowane DataSet generowane z XML schema Dostęp do DataSet poprzez interfejs XML-DOM Integracja w systemach rozproszon Silna integracja serializacjaDataSet do XML XML jako źródło danych dla DataSet Schema dla DataSets zdefiniowana jako XML schemas
Metody klasy DataSet do obsługi danych i schematów XML ReadXML – Ładowanie XML WriteXml - zapis DataSet do strumienia XML WriteXmlSchema – wygenerowanie schemy z DataSet ReadXmlSchema – załadowanie XML Schema InferXmlSchema – stworzenie schemy DataSet na podstawie XML GetXml i GetXmlSchema – zwraca ciąg XML lub XML Schema
Metody klasy DataSet do obsługi danych i schematów XML Use ReadXml to load data from a file or stream Use WriteXml to write XML data to a file or stream Use GetXml to write data to a string variable DataSet ds = new DataSet(); ds.ReadXml(Server.MapPath("filename.xml")); DataSet ds = new DataSet(); SqlDataAdapter da = new SqlDataAdapter("select * from Authors", conn); da.Fill(ds); ds.WriteXml(Server.MapPath("filename.xml")); string strXmlDS = ds.GetXml();
Synchronizacja DataSet z XmlDataDocument Załadowanie XML Data do XmlDataDocument XmlDataDocument objXmlDataDoc = new XmlDataDocument(); objXmlDataDoc.Load(Server.MapPath ("file.xml")); Załadowanie DataSet do XmlDataDocument DataSet ds = new DataSet(); //fill in ds objXmlDataDoc = new XmlDataDocument(ds); XmlDataDocument objXmlDataDoc = new XmlDataDocument(); objXmlDataDoc.Load(Server.MapPath ("file.xml")); -or- objXmlDataDoc.DataSet.ReadXml(Server.MapPath ("file.xml"));
Praca z XmlDataDocument Załadowanie danych Pobranie wierszy jako XML Metody XML DOM XmlDataDocument dziedziczy z XmlDocument dg.DataSource = objXmlDataDoc.DataSet; XmlElement elem; elem = objXmlDataDoc.GetElementFromRow(ds.Tables[0].Rows[1]); The DataSet represents a relational data source in ADO.NET. The XmlDocument implements the DOM in XML, and the XmlDataDocument unifies ADO.NET and XML by representing relational data from a DataSet and synchronizing that data with the XML document model. The DataGrid control displays all of the rows in the table within the DataSet. The following code demonstrates how to assign the DataSet object (objXmlDataDoc.DataSet) to the DataGrid control (dg): To extract individual rows as XML, you need to query the DataSet. To query the DataSet, you use the GetElementFromRow method. The following code demonstrates how the GetElementFromRow method of XmlDataDocument returns an XmlElement object The.NET Framework implements the XML DOM to provide access to data in XML documents and to provide access to the additional classes to read, write, and navigate within XML documents. The XmlDataDocument provides relational access to data with its ability to synchronize with the relational data in the DataSet. The XmlDataDocument class extends the XmlDocument class. Because the XmlDocument class implements the DOM, it enables you to load either relational data or XML data. The XmlDataDocument also allows you to manipulate that data by using the DOM. If data is stored in a relational structure and you want it to be input into an XSLT transformation, you can load the relational data into a DataSet and then associate it with the XmlDataDocument. By taking relational data, loading it into a DataSet, and using the synchronizing within the XmlDataDocument, the relational data can have XSLT transformations performed on it. The XslTransform object transforms XML data by using an XSLT style sheet.