Datenzugriff mit ADO.NET Dirk Primbs Technologieberater Microsoft Deutschland GmbH...

Post on 05-Apr-2015

106 views 0 download

Tags:

transcript

Datenzugriff mit ADO.NET

Dirk PrimbsTechnologieberaterMicrosoft Deutschland GmbHdirkp@microsoft.com

<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 GmbHdirkp@microsoft.com

Dirk PrimbsTechnologieberaterMicrosoft Deutschland GmbHdirkp@microsoft.com

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