Upload
heinrike-schlageter
View
111
Download
0
Tags:
Embed Size (px)
Citation preview
Datenzugriff mit ADO.NET
Dirk PrimbsTechnologieberaterMicrosoft Deutschland [email protected]
<Agenda topic="ADO.NET"><Architektur /><Datenzugriff /><XML /><DataBinding /><Ausblick />
</Agenda>
<Agenda topic="ADO.NET"><Architektur /><Datenzugriff /><XML /><DataBinding /><Ausblick />
</Agenda>
Ein Blick auf die ArchitekturEin Blick auf die Architektur
Managed Provider
DataReader
CommandConnection
Sync
Controls,Designers,
Code-gen, etc
DataSet
XmlReader
XmlText-Reader
XmlNode-Reader
XSL/T, X-Path, etc
XmlData-Document
DataAdapter
Das DataSet im DetailDas DataSet im Detail
DataSetDataSet
DataTableCollectionDataTableCollection
DataTableDataTable
DataViewDataViewDataRowCollectionDataRowCollectionDataColumnCollectionDataColumnCollection
DataRelationCollectionDataRelationCollection
ADO.NET 2.0ADO.NET 2.0
DesignzieleVerbesserung der Performance (~30%)Weniger CodeNo breaking changes!
DesignzieleVerbesserung der Performance (~30%)Weniger CodeNo breaking changes!
ADO.NET 2.0ADO.NET 2.0
SQL Server Yukon FeaturesNotification ServicesXML Data TypesBulk CopyMultiple Active Resultsets (MARS)
Common Provider ModelDataSet
Automatische Ermittlung von BeziehungenBinary Serialization
SQL Server Yukon FeaturesNotification ServicesXML Data TypesBulk CopyMultiple Active Resultsets (MARS)
Common Provider ModelDataSet
Automatische Ermittlung von BeziehungenBinary Serialization
© 2004 Microsoft Corporation. All rights reserved.© 2004 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.
AnhangAnhang
Einführung in ADO.NETEinführung in ADO.NET
Kein einfacher Nachfolger von ADONeues Paradigma und ObjektmodellArchitektur Schwerpunkt: Daten losgelöst von der Datenbank zu bearbeitenAnders anzuwenden, macht aber auch vieles einfacher
z.B. Implementierung eigener Provider
Kein einfacher Nachfolger von ADONeues Paradigma und ObjektmodellArchitektur Schwerpunkt: Daten losgelöst von der Datenbank zu bearbeitenAnders anzuwenden, macht aber auch vieles einfacher
z.B. Implementierung eigener Provider
Ein Blick auf die ArchitekturEin Blick auf die Architektur
Managed Provider
DataReader
CommandConnection
Sync
Controls,Designers,
Code-gen, etc
DataSet
XmlReader
XmlText-Reader
XmlNode-Reader
XSL/T, X-Path, etc
XmlData-Document
DataAdapter
Managed ProviderManaged Provider
Um auf Daten zuzugreifen benötigt man einen Managed ProviderDer Managed Provider implementiert die notwendigen Schnittstellen
IDbConnectionIDbCommandIDataReader
Diese Schnittstellen sind im Namespace System.Data beschrieben
Um auf Daten zuzugreifen benötigt man einen Managed ProviderDer Managed Provider implementiert die notwendigen Schnittstellen
IDbConnectionIDbCommandIDataReader
Diese Schnittstellen sind im Namespace System.Data beschrieben
Managed Provider IIManaged Provider II
Zwei Provider sind bei der Visual Studio .NET Version dabei
SQL Server Managed ProviderSystem.Data.SqlClient
OLEDB Managed ProviderSystem.Data.OleDb
Zwei weitere sind noch verfügbarOracle Managed ProviderODBC Managed Provider
zu finden unter http://msdn.microsoft.com
Zwei Provider sind bei der Visual Studio .NET Version dabei
SQL Server Managed ProviderSystem.Data.SqlClient
OLEDB Managed ProviderSystem.Data.OleDb
Zwei weitere sind noch verfügbarOracle Managed ProviderODBC Managed Provider
zu finden unter http://msdn.microsoft.com
Das Connection ObjektDas Connection Objekt
Mit dem Connection Objekt wird die Verbindung zur Datenquelle hergestellt
Mit dem Connection Objekt wird die Verbindung zur Datenquelle hergestellt
using System.Data;using System.Data;using System.Data.SqlClient;using System.Data.SqlClient;......public void ConnectToDatabase()public void ConnectToDatabase(){{ SqlConnection conn = new SqlConnection();SqlConnection conn = new SqlConnection(); conn.ConnectionString = „{providerspecific string}“;conn.ConnectionString = „{providerspecific string}“; conn.Open();conn.Open();}}
Das Command ObjektDas Command Objekt
Das Command Objekt führt die entsprechenden Befehle gegen die Datenquelle aus
In der Regel SQL StatementsBei manchen Providern auch andere Statements
Command Objekte können referenzen auf andere Objekte zurückgeben
z.B. ExecuteReader()
Das Command Objekt führt die entsprechenden Befehle gegen die Datenquelle aus
In der Regel SQL StatementsBei manchen Providern auch andere Statements
Command Objekte können referenzen auf andere Objekte zurückgeben
z.B. ExecuteReader()
Das Command Objekt IIDas Command Objekt II
Benötigt eine ConnectionOptional auch eigene TransaktionBenötigt eine ConnectionOptional auch eigene Transaktion
using System.Data;using System.Data;using System.Data.SqlClient;using System.Data.SqlClient;......public void ExecuteSomething()public void ExecuteSomething(){{ ...... SqlCommand cmd = new SqlCommand( „DELETE FROM a“ );SqlCommand cmd = new SqlCommand( „DELETE FROM a“ ); cmd.ExecuteNoQuery();cmd.ExecuteNoQuery(); ......}}
Das DataReader ObjektDas DataReader Objekt
Über das Reader Objekt werden die Daten aus einem Resultset ausgelesenNur Vorwärtslesen möglich!
Über das Reader Objekt werden die Daten aus einem Resultset ausgelesenNur Vorwärtslesen möglich!......
public void ReadData()public void ReadData(){{ ...... SqlDataReader reader = cmd.ExecuteReader(); SqlDataReader reader = cmd.ExecuteReader(); while( reader.Read() )while( reader.Read() ) { Console.WriteLine( reader.GetString( 1 ) ); }{ Console.WriteLine( reader.GetString( 1 ) ); } ......}}
DataAdapter und DataSetDataAdapter und DataSet
Daten können aus der Datenquelle in ein Objekt gelesen werden
DataSet
Daten können aus diesem Objekt wieder in die Datenquelle geschrieben werden
durch den DataAdapter
Daten können aus der Datenquelle in ein Objekt gelesen werden
DataSet
Daten können aus diesem Objekt wieder in die Datenquelle geschrieben werden
durch den DataAdapter
Das DataAdapter ObjektDas DataAdapter Objekt
Die Brücke zwischen Datenquelle und DataSetÖffnet die Verbindung automatisch
falls noch nicht offen
Schliesst die Verbindung automatischfalls diese selbst geöffnet wurde
Die wichtigsten Methoden hierbei sindFill()Update()
Die Brücke zwischen Datenquelle und DataSetÖffnet die Verbindung automatisch
falls noch nicht offen
Schliesst die Verbindung automatischfalls diese selbst geöffnet wurde
Die wichtigsten Methoden hierbei sindFill()Update()
Das DataAdapter Objekt IIDas DataAdapter Objekt II
Als Grundlage dienen 4 StatementsSelectCommandInsertCommandDeleteCommandUpdateCommand
Das CommandBuilder Objekt kann dabei fehlende Befehle selbst erzeugen
Als Grundlage dienen 4 StatementsSelectCommandInsertCommandDeleteCommandUpdateCommand
Das CommandBuilder Objekt kann dabei fehlende Befehle selbst erzeugen
Das DataSet ObjektDas DataSet Objekt
Das zentrale Element für DatenbearbeitungEin Objekt das Daten im Speicher der Anwendung hältHat keinerlei Information woher die Daten kamen und wohin diese gehen
Das weiß der DataAdapter
Das zentrale Element für DatenbearbeitungEin Objekt das Daten im Speicher der Anwendung hältHat keinerlei Information woher die Daten kamen und wohin diese gehen
Das weiß der DataAdapter
Das DataSet ObjektDas DataSet Objekt
Direkte Nutzung der KlasseDataSet ds = new DataSet();
Man kann auch eine typisierte Version des Objektes nutzen
Eine Ableitung von DataSet die das Layout der Tabelle als Klasse wiedergibtEin Code Generator erzeugt diese Klasse
Direkte Nutzung der KlasseDataSet ds = new DataSet();
Man kann auch eine typisierte Version des Objektes nutzen
Eine Ableitung von DataSet die das Layout der Tabelle als Klasse wiedergibtEin Code Generator erzeugt diese Klasse
Das DataSet im DetailDas DataSet im Detail
DataSetDataSet
DataTableCollectionDataTableCollection
DataTableDataTable
DataViewDataViewDataRowCollectionDataRowCollectionDataColumnCollectionDataColumnCollection
DataRelationCollectionDataRelationCollection
DataSet im DetailDataSet im Detail
Enthält also Tabellen, Relationen, Views und ConstraintsEine kleine „In-Memory“ DatenbankDaten werden XML basiert behandelt!
DataSets basieren auf XML SchemasDataSets können mit XmlDataDocument synchronisiert werden
Enthält also Tabellen, Relationen, Views und ConstraintsEine kleine „In-Memory“ DatenbankDaten werden XML basiert behandelt!
DataSets basieren auf XML SchemasDataSets können mit XmlDataDocument synchronisiert werden
Datenbindung in .NETDatenbindung in .NET
DataBindingherstellen einer Verbindung zwischen Datencontainer und Datenelement
Datenbindung mit jeglichem Objekt möglich
DataSetArrayDataReadereigene Objekte
Bestimmte Schnittstellen müssen Implementiert werden
DataBindingherstellen einer Verbindung zwischen Datencontainer und Datenelement
Datenbindung mit jeglichem Objekt möglich
DataSetArrayDataReadereigene Objekte
Bestimmte Schnittstellen müssen Implementiert werden
Arten von DatenbindungArten von Datenbindung
Zwei unterschiedliche Arten von Bindung
Einfache Datenbindungkomplexe Datenbindung
Die Relation zwischen einem Anzeigeelement und einem Datenelement
z.B. TextBox.Text = Customers.Lastname
Oder zwischen einem Steuerelement und einem Datencontainer
z.B. DataGrid.DataSource = DataSet
Zwei unterschiedliche Arten von Bindung
Einfache Datenbindungkomplexe Datenbindung
Die Relation zwischen einem Anzeigeelement und einem Datenelement
z.B. TextBox.Text = Customers.Lastname
Oder zwischen einem Steuerelement und einem Datencontainer
z.B. DataGrid.DataSource = DataSet
Herstellen der BindungHerstellen der Bindung
Die Datenbindung kannwährend des Anwendungsdesigns gemacht werdenzur Laufzeit gemacht werden
Bindungen können jeder Zeit wieder gelöst und neu getätigt werdenDas BindingManager Objekt verwaltet diese Datenbindungen
Die Datenbindung kannwährend des Anwendungsdesigns gemacht werdenzur Laufzeit gemacht werden
Bindungen können jeder Zeit wieder gelöst und neu getätigt werdenDas BindingManager Objekt verwaltet diese Datenbindungen
ADO.NET und XMLADO.NET und XML
XML ist die Grundlage von ADO.NETDaten können in beide Richtungen ausgetauscht werden
DataSet -> XmlDataDocumentXmlDataDocument -> DataSet
Neue Möglichkeiten mit relationalen Daten zu arbeiten
Hierarchische SichtweiseXPath QueriesXSLT Umwandlungen
XML ist die Grundlage von ADO.NETDaten können in beide Richtungen ausgetauscht werden
DataSet -> XmlDataDocumentXmlDataDocument -> DataSet
Neue Möglichkeiten mit relationalen Daten zu arbeiten
Hierarchische SichtweiseXPath QueriesXSLT Umwandlungen
ZusammenfassungZusammenfassung
ADO.NET ist ein neu zu erlernendes ObjektmodellAber es ist einfacher zu benutzenUnd einfacher zu erweiternBietet volle Zugriffsmöglichkeit auf relationale und XML basierte Datenbestände
ADO.NET ist ein neu zu erlernendes ObjektmodellAber es ist einfacher zu benutzenUnd einfacher zu erweiternBietet volle Zugriffsmöglichkeit auf relationale und XML basierte Datenbestände
ADO.NET 2.0ADO.NET 2.0
Dirk PrimbsTechnologieberaterMicrosoft Deutschland [email protected]
Dirk PrimbsTechnologieberaterMicrosoft Deutschland [email protected]
AgendaAgenda
ADO.NET 2.0 im ÜberblickADO.NET most wanted
EinfacherSchnellerUnterstützung für SQL Server "Yukon"Demos, Demos, Demos, ...
ADO.NET 2.0 im ÜberblickADO.NET most wanted
EinfacherSchnellerUnterstützung für SQL Server "Yukon"Demos, Demos, Demos, ...
Ziele bei der Entwicklung von ADO.NET 2.0Ziele bei der Entwicklung von ADO.NET 2.0
Evolution, nicht RevolutionUmsetzen von Kundenwünschen
Viele Features wurden durch Kundenwunsch getrieben
Mehr Möglichkeiten für Spezialisten
Performance, Performance, Performance
Support für SQL Server "Yukon" als First Class Feature
Evolution, nicht RevolutionUmsetzen von Kundenwünschen
Viele Features wurden durch Kundenwunsch getrieben
Mehr Möglichkeiten für Spezialisten
Performance, Performance, Performance
Support für SQL Server "Yukon" als First Class Feature
Keine fundamentalen Änderungen des Objektmodells!
Was unter ADO.NET 1.1 funktioniert, geht auch unter Whidbey!
Top 3 KundenwünscheTop 3 Kundenwünsche
Paging großer Datenmengenautomatische Übernahme von Beziehungen in typisierten DataSetsServerseitiger Cursor
Paging großer Datenmengenautomatische Übernahme von Beziehungen in typisierten DataSetsServerseitiger Cursor
Paging von AbfrageergebnissenPaging von Abfrageergebnissen
Häufiger Wunsch besonders von Web-Entwicklern
HTTP ist zustandsloszu übertragende Datenmenge ist performance-kritisch
SqlCommand.ExecutePageReader()Optional von Datenprovidern implementierbarNutzt bei SQL Server intern Stored Procedures sp_cursoropen und sp_cursorfetch
Häufiger Wunsch besonders von Web-Entwicklern
HTTP ist zustandsloszu übertragende Datenmenge ist performance-kritisch
SqlCommand.ExecutePageReader()Optional von Datenprovidern implementierbarNutzt bei SQL Server intern Stored Procedures sp_cursoropen und sp_cursorfetch
Beziehungen und typisierte DataSetsBeziehungen und typisierte DataSets
Bisher mußten Beziehungen zwischen Datentabellen manuell am DataSet modelliert werden
ds.Relations.Add()
In Whidbey können diese Beziehungen automatisiert ermittelt und auf das DataSet angewandt werden
Bisher mußten Beziehungen zwischen Datentabellen manuell am DataSet modelliert werden
ds.Relations.Add()
In Whidbey können diese Beziehungen automatisiert ermittelt und auf das DataSet angewandt werden
Serverseitiger CursorServerseitiger Cursor
Nur einsetzen, wenn unbedingt notwendig!
Kann Resourcen-/Skalierungsprobleme verursachen
SqlCommand.ExecuteResultSet();Als Scrollable und als Updatable möglich
Nur einsetzen, wenn unbedingt notwendig!
Kann Resourcen-/Skalierungsprobleme verursachen
SqlCommand.ExecuteResultSet();Als Scrollable und als Updatable möglich
SqlConnection sqlConn = new SqlConnection(strConn);SqlCommand sqlCmd = sqlConn.CreateCommand();sqlCmd.CommandText = strSQL;
sqlResultSet sqlResults = sqlCmd.ExecuteResultSet(ResultSetOptions.Updatable |
ResultSetOptions.Scrollable);
Provider-FactoriesProvider-Factories
Enumerieren vorhandener ADO.NET-Provider
DbProviderFactories.GetFactoryClasses()
Dynamisches Erzeugen aller wichtigen Objekte
Enumerieren vorhandener ADO.NET-Provider
DbProviderFactories.GetFactoryClasses()
Dynamisches Erzeugen aller wichtigen Objekte
DbProviderFactory provFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
DbDataAdapter da = provFactory.CreateDataAdapter();
da.Connection = provFactory.CreateConnection();da.Connection.ConnectionString = "...";da.SelectCommand = provFactory.CreateCommand();da.SelectCommand.CommandText = "select * from customers";
da.Fill(ds);
Enumerieren…Enumerieren…
... durch alle verfügbaren Provider
... durch Serverinstanzen im Netzwerk
... durch alle verfügbaren Provider
... durch Serverinstanzen im NetzwerkDataTable sources =
SqlDataSourceEnumerator.Instance.GetDataSources();
foreach( DataRow dr in sources.Rows ) { Console.WriteLine("{0}", dr["Name"]);}
DataTable providers = DbProviderFactories.GetFactoryClasses();
foreach (DataRow dr in providers.Rows) { Console.WriteLine("Name: {0}, Invariantname: {1}",
dr["Name"], dr["Invariantname"]}
Asynchroner DatenzugriffAsynchroner Datenzugriff
Ideal überall dort wo das Blockieren des Ausführungsthreads verhindert werden soll
Client-Applikationen: UI-ThreadServer-ApplikationenBeginOpen, EndOpen, BeginExecute, …
Integrierbar in 3rd Party ProvidersADO.NET 2.0 unterstützt asynchronen Zugriff bei SQL Server 7, 2000 und “Yukon”
Ideal überall dort wo das Blockieren des Ausführungsthreads verhindert werden soll
Client-Applikationen: UI-ThreadServer-ApplikationenBeginOpen, EndOpen, BeginExecute, …
Integrierbar in 3rd Party ProvidersADO.NET 2.0 unterstützt asynchronen Zugriff bei SQL Server 7, 2000 und “Yukon”
DataSet PerformanceDataSet Performance
RemotingEin häufiger Hinweis unserer Kunden:
“DataSets sind langsam, wenn man sie mit Remoting benutzt”
Deshalb…Datasets unterstützen jetzt "binary serialization"Deutlich schnelleres serialize/deserializeDeutlich weniger Speicherverbrauch
Neues, schnelleres IndexingSpeziell bei Insert deutliche Performancesteigerungen
RemotingEin häufiger Hinweis unserer Kunden:
“DataSets sind langsam, wenn man sie mit Remoting benutzt”
Deshalb…Datasets unterstützen jetzt "binary serialization"Deutlich schnelleres serialize/deserializeDeutlich weniger Speicherverbrauch
Neues, schnelleres IndexingSpeziell bei Insert deutliche Performancesteigerungen
Bulk Copy Bulk Copy
beschleunigt das Kopieren größerer Datenmengen
SqlBulkCopyOperationkann DataReader oder DataTable als Datenquelle verwendendeutlich bessere Performance als entsprechende Insert-Kommandos
beschleunigt das Kopieren größerer Datenmengen
SqlBulkCopyOperationkann DataReader oder DataTable als Datenquelle verwendendeutlich bessere Performance als entsprechende Insert-Kommandos
Batch UpdatesBatch Updates
ADO.NET 1.0/1.1: DataAdapter.Update() erzeugt pro Row einen Roundtrip zum ServerIn Whidbey kann blockweise geupdatet werden:
adapter.UpdateBatchSize = your_batch_size
Verfügbar für SqlClient and OracleClientBatches können innerhalb einer Transaktion durchgeführt werden
Dazu Transaktionsobjekt der Commands am Dataadapter setzen
ADO.NET 1.0/1.1: DataAdapter.Update() erzeugt pro Row einen Roundtrip zum ServerIn Whidbey kann blockweise geupdatet werden:
adapter.UpdateBatchSize = your_batch_size
Verfügbar für SqlClient and OracleClientBatches können innerhalb einer Transaktion durchgeführt werden
Dazu Transaktionsobjekt der Commands am Dataadapter setzen
Multiple Active Result-SetsMultiple Active Result-Sets
Mehr als ein aktiver Request pro Connection-Objekt
Mehrer aktive DataReaderAusführung von Batches zwischen Read() und Read()Ein aktiver DataReader pro Command-Objekt
basiert auf SQL Server "Yukon" MARS
Mehr als ein aktiver Request pro Connection-Objekt
Mehrer aktive DataReaderAusführung von Batches zwischen Read() und Read()Ein aktiver DataReader pro Command-Objekt
basiert auf SQL Server "Yukon" MARS
System.InvalidOperationException: There is already an open DataReader associated with this Connection which must be closed first.
Benutzerdefinierte DatentypenBenutzerdefinierte Datentypen
CLR-Typen direkt in die Datenbank schreibenNahtlose Integration in ADO.NET
Übergabe der Objekte durch …… datareader.GetValue … Parameter.Value=…
Wird in SQL Server "Yukon" unterstützt
CLR-Typen direkt in die Datenbank schreibenNahtlose Integration in ADO.NET
Übergabe der Objekte durch …… datareader.GetValue … Parameter.Value=…
Wird in SQL Server "Yukon" unterstützt
SQL Server XML DatentypSQL Server XML DatentypNahtlose Integration
“Einfach nur ein Typ”DataReader
SqlDataReader.GetSqlXmlReader
ParameterEinfach einen XmlReader oder einen string übergeben
DataSetAnsteuerbar als XPathDocumentHinweis: In der Alpha-Version von Whidbey enthält das DataSet statt dessen einen XmlReader
Nahtlose Integration“Einfach nur ein Typ”DataReader
SqlDataReader.GetSqlXmlReader
ParameterEinfach einen XmlReader oder einen string übergeben
DataSetAnsteuerbar als XPathDocumentHinweis: In der Alpha-Version von Whidbey enthält das DataSet statt dessen einen XmlReader
Common Provider ModelCommon Provider ModelADO.NET v1.0/1.1 basiert auf Interfaces
Reicht nicht immer aus um providerunabhängigen Code zu schreibenAufwändige Implementation für eigene Provider notwendig
Deshalb: ein gemeinsames Basis-ObjektmodellAbstrakte Basisklassen statt Interfaces
Vereinfacht die Versionierung3rd Party Provider können ADO.NET Basisfunktionalität mitbenutzen.
z.B. ADO.NET Connection Pooler
Ideale Grundlage für Provider-unabhängige ApplikationenBasisklassen sind eine Erweiterung des bisherigen Modells => Keine Kompatibilitätsprobleme
ADO.NET v1.0/1.1 basiert auf InterfacesReicht nicht immer aus um providerunabhängigen Code zu schreibenAufwändige Implementation für eigene Provider notwendig
Deshalb: ein gemeinsames Basis-ObjektmodellAbstrakte Basisklassen statt Interfaces
Vereinfacht die Versionierung3rd Party Provider können ADO.NET Basisfunktionalität mitbenutzen.
z.B. ADO.NET Connection Pooler
Ideale Grundlage für Provider-unabhängige ApplikationenBasisklassen sind eine Erweiterung des bisherigen Modells => Keine Kompatibilitätsprobleme
Gemeinsame BasisklassenGemeinsame Basisklassen
System.Data.ProviderBaseAbstrakte Basisklassen für alle wichtigen ProviderobjekteKönnen in eigenen Providern als Ableitungsbasis verwendet und um eigene Funktionalität ergänzt werden
System.Data.ProviderBaseAbstrakte Basisklassen für alle wichtigen ProviderobjekteKönnen in eigenen Providern als Ableitungsbasis verwendet und um eigene Funktionalität ergänzt werden
Was sonst noch…Was sonst noch…
Integration mit System.TransactionsTracingConnection pool reset APIDataSet
DataTable losgelöster von DataSetDataSet.LoadDataTableReader
Integration mit System.TransactionsTracingConnection pool reset APIDataSet
DataTable losgelöster von DataSetDataSet.LoadDataTableReader
SqlClientNotificationsSQL Server ‘Yukon’ Typen
varchar/varbinary(max)
Change password on loginPromotable transactionsMore to come…
OleDbManaged pooling option
SqlClientNotificationsSQL Server ‘Yukon’ Typen
varchar/varbinary(max)
Change password on loginPromotable transactionsMore to come…
OleDbManaged pooling option
ZusammenfassungZusammenfassung
Whidbey: Änderungen basieren größtenteils auf Kundenfeedback
Features, Performance, Usability
IntegrationSQL Server “Yukon” wird nativ unterstützt
Evolution statt RevolutionKeine Kompatibilitätsprobleme
Whidbey: Änderungen basieren größtenteils auf Kundenfeedback
Features, Performance, Usability
IntegrationSQL Server “Yukon” wird nativ unterstützt
Evolution statt RevolutionKeine Kompatibilitätsprobleme