Aktualisieren von Datenquellen mit DataAdapters
Gilt für: .NET Framework .NET .NET Standard
Zum Aktualisieren von Datenquellen mit den Änderungen, die an einem Update
vorgenommen wurden, wird die DataAdapter-Methode des DataSet aufgerufen. Als Argumente akzeptiert die Update
-Methode, genau wie die Fill
-Methode, eine Instanz eines DataSet
sowie ein optionales DataTable-Objekt oder einen DataTable
-Namen. Die DataSet
-Instanz ist das DataSet
, das die vorgenommenen Änderungen enthält, und der DataTable
-Wert gibt die Tabelle an, aus der die Änderungen abgerufen werden sollen. Wenn keine DataTable
angegeben ist, wird die erste DataTable
im DataSet
verwendet.
Wenn die Update
-Methode aufgerufen wird, analysiert der DataAdapter
die vorgenommenen Änderungen und führt dann den entsprechenden Befehl (INSERT, UPDATE oder DELETE) aus. Wenn der DataAdapter
eine Änderung an einer DataRow feststellt, verwendet er zum Verarbeiten der Änderung den InsertCommand, den UpdateCommand oder den DeleteCommand.
Diese Eigenschaften ermöglichen es Ihnen, die Leistung Ihrer ADO.NET-Anwendung zu maximieren, indem Sie die Befehlssyntax zur Entwurfszeit festlegen und nach Möglichkeit gespeicherte Prozeduren verwenden. Sie müssen die Befehle vor dem Aufrufen von Update
explizit festlegen. Wenn Update
aufgerufen wird und der entsprechende Befehl für ein bestimmtes Update nicht vorhanden ist (wenn z. B. DeleteCommand
für gelöschte Zeilen fehlt), wird eine Ausnahme ausgelöst.
Wichtig
Wenn Sie gespeicherte SQL Server-Prozeduren verwenden, um Daten mithilfe einer DataAdapter
-Klasse zu bearbeiten oder zu löschen, stellen Sie sicher, dass Sie in der Definition der gespeicherten Prozedur nicht SET NOCOUNT ON
verwenden. Anderenfalls ist die zurückgegebene Anzahl der betroffenen Zeilen gleich Null (0), was der DataAdapter
als Parallelitätskonflikt interpretiert. In diesem Fall wird eine DBConcurrencyException ausgelöst.
Befehlsparameter können verwendet werden, um Eingabe- und Ausgabewerte für eine SQL-Anweisung oder gespeicherte Prozedur für jede geänderte Zeile in einer .DataSet
Weitere Informationen finden Sie unter DataAdapter-Parameter.
Hinweis
Wichtig ist dabei, zwischen dem Löschen einer Zeile in einer DataTable und dem Entfernen der Zeile zu unterscheiden. Wenn Sie die Remove
-Methode oder die RemoveAt
-Methode aufrufen, wird die Zeile sofort entfernt. Die entsprechenden Zeilen in der Back-End-Datenquelle sind nicht betroffen, wenn Sie anschließend die DataTable
- oder DataSet
-Klasse an eine DataAdapter
-Klasse übergeben und Update
aufrufen. Wenn Sie die Methode Delete
verwenden, bleibt die Zeile in der DataTable
erhalten, wird aber als zu löschen markiert. Wenn Sie dann die DataTable
- oder DataSet
-Klasse an eine DataAdapter
-Klasse übergeben und Update
aufrufen, wird die entsprechende Zeile in der Back-End-Datenquelle gelöscht.
Wenn Ihre DataTable
einer einzelnen Datenbanktabelle zugeordnet ist oder aus einer einzelnen Datenbanktabelle generiert wurde, können Sie mithilfe des DbCommandBuilder-Objekts automatisch das DeleteCommand
-, das InsertCommand
- und das UpdateCommand
-Objekt für den DataAdapter
generieren. Weitere Informationen finden Sie unter Generieren von Befehlen mit CommandBuilder-Klassen.
Verwenden von UpdatedRowSource für die Zuordnung von Werten zu einer DataSet-Klasse
Mithilfe der UpdatedRowSource-Eigenschaft eines SqlCommand-Objekts können Sie steuern, wie nach dem Aufrufen der Update-Methode einer DataAdapter
-Klasse die von der Datenquelle zurückgegebenen Werte wieder der DataTable
-Klasse zugeordnet werden. Durch Festlegen eines der UpdatedRowSource
-Enumerationswerte für die UpdateRowSource-Eigenschaft kann gesteuert werden, ob die von den DataAdapter
-Befehlen zurückgegebenen Ausgabeparameter ignoriert oder auf die geänderte Zeile im DataSet
angewendet werden. Es kann auch festgelegt werden, ob die erste zurückgegebene Zeile (wenn vorhanden) auf die geänderte Zeile in der DataTable
angewendet wird.
In der folgenden Tabelle werden die verschiedenen Werte der UpdateRowSource
-Enumeration und deren Auswirkungen auf das Verhalten eines mit einem DataAdapter
verwendeten Befehls beschrieben.
"UpdatedRowSource"-Enumeration | BESCHREIBUNG |
---|---|
Both | Sowohl die Ausgabeparameter als auch die erste Zeile eines zurückgegebenen Resultset können der geänderten Zeile im DataSet zugeordnet werden. |
FirstReturnedRecord | Nur die Daten in der ersten Zeile eines zurückgegebenen Resultset können der geänderten Zeile im DataSet zugeordnet werden. |
None | Alle Ausgabeparameter oder Zeilen eines zurückgegebenen Resultset werden ignoriert. |
OutputParameters | Der geänderten Zeile im DataSet können nur Ausgabeparameter zugeordnet werden. |
Die Update
-Methode aktualisiert die Datenquelle mit den vorgenommenen Änderungen. Die Daten in der Datenquelle können aber seit dem letzten Füllen des DataSet
durch andere Clients geändert worden sein. Wenn Sie das DataSet
mit den aktuellen Daten aktualisieren möchten, verwenden Sie den DataAdapter
und die Fill
-Methode. Der Tabelle werden neue Zeilen hinzugefügt, und aktualisierte Informationen werden in die vorhandenen Zeilen eingefügt.
Die Fill
-Methode überprüft die Primärschlüsselwerte der Zeilen im DataSet
und der vom SelectCommand
zurückgegebenen Zeilen und bestimmt so, ob eine neue Zeile hinzugefügt oder die bestehende Zeile aktualisiert werden soll. Wenn die Fill
-Methode einen Primärschlüsselwert für eine Zeile im DataSet
findet, der mit einem Primärschlüsselwert einer Zeile in den vom SelectCommand
zurückgegebenen Ergebnissen übereinstimmt, aktualisiert sie die vorhandene Zeile mit den Informationen aus der vom SelectCommand
zurückgegebenen Zeile und legt den RowState der vorhandenen Zeile auf Unchanged
fest. Wenn der Primärschlüsselwert einer vom SelectCommand
zurückgegebenen Zeile keinem der Primärschlüsselwerte der Zeilen im DataSet
entspricht, fügt die Fill
-Methode eine neue Zeile mit dem RowState
Unchanged
hinzu.
Hinweis
Wenn die SelectCommand
-Eigenschaft die Ergebnisse eines OUTER JOIN-Vorgangs zurückgibt, legt die DataAdapter
-Klasse für die resultierende DataTable
-Klasse keinen PrimaryKey
-Wert fest. Sie müssen den PrimaryKey
selbst definieren, um sicherzustellen, dass doppelte Zeilen ordnungsgemäß aufgelöst werden.
Zur Behandlung von Ausnahmen, die beim Aufrufen der Update
-Methode auftreten können, können Sie das RowUpdated
-Ereignis verwenden, um auf beim Aktualisieren von Zeilen auftretende Fehler zu reagieren (siehe Umgang mit DataAdapter-Ereignissen). Alternativ können Sie true
für ContinueUpdateOnError festlegen, bevor Sie Update
aufrufen, und auf die in der RowError
-Eigenschaft einer bestimmten Zeile gespeicherten Fehlerinformationen reagieren, wenn das Update abgeschlossen ist.
Hinweis
Wenn AcceptChanges
für die DataSet
-, DataTable
- oder DataRow
-Klasse aufgerufen wird, werden alle Original
-Werte einer DataRow
-Klasse mit den Current
-Werten für die DataRow
-Klasse überschrieben. Wenn die Feldwerte, mit denen die Zeile als eindeutig identifiziert wird, geändert wurden, stimmen die AcceptChanges
-Werte nicht mehr mit den Werten in der Datenquelle überein, nachdem Original
aufgerufen wurde. Während eines Aufrufs der Update
-Methode einer DataAdapter
-Klasse wird AcceptChanges
automatisch für jede Zeile aufgerufen. Sie können die Originalwerte während eines Aufrufs der Update-Methode beibehalten, indem Sie zuerst die -Eigenschaft des auf false setzen oder indem Sie einen Ereignishandler für das -Ereignis erstellen und den auf festlegen. Weitere Informationen finden Sie unter Umgang mit DataAdapter-Ereignissen.
Die folgenden Beispiele zeigen, wie geänderte Zeilen aktualisiert werden können, indem die UpdateCommand
-Eigenschaft einer DataAdapter
-Klasse explizit festgelegt und deren Update
-Methode aufgerufen wird.
Hinweis
Der in der WHERE clause
der UPDATE statement
angegebene Parameter wird so festgelegt, dass der Original
-Wert der SourceColumn
-Eigenschaft verwendet wird. Dies ist wichtig, weil der Current
-Wert möglicherweise geändert wurde und u. U. nicht mehr mit dem Wert in der Datenquelle übereinstimmt. Beim Original
-Wert handelt es sich um den Wert, mit dem die DataTable
aus der Datenquelle aufgefüllt wurde.
private static void AdapterUpdate(string connectionString)
{
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlDataAdapter dataAdpater = new SqlDataAdapter(
"SELECT CategoryID, CategoryName FROM Categories",
connection);
dataAdpater.UpdateCommand = new SqlCommand(
"UPDATE Categories SET CategoryName = @CategoryName " +
"WHERE CategoryID = @CategoryID", connection);
dataAdpater.UpdateCommand.Parameters.Add(
"@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");
SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(
"@CategoryID", SqlDbType.Int);
parameter.SourceColumn = "CategoryID";
parameter.SourceVersion = DataRowVersion.Original;
DataTable categoryTable = new DataTable();
dataAdpater.Fill(categoryTable);
DataRow categoryRow = categoryTable.Rows[0];
categoryRow["CategoryName"] = "New Beverages";
dataAdpater.Update(categoryTable);
Console.WriteLine("Rows after update.");
foreach (DataRow row in categoryTable.Rows)
{
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
}
}
}
AutoIncrement-Spalten
Wenn die Tabellen aus der Datenquelle automatisch inkrementierende Spalten besitzen, können Sie die Spalten im DataSet
füllen. Geben Sie dazu die automatisch inkrementierenden Werte als Ausgabeparameter einer gespeicherten Prozedur zurück, und ordnen Sie diesen Parameter einer Spalte in einer Tabelle zu, indem Sie den automatisch inkrementierenden Wert in der ersten Zeile eines von einer gespeicherten Prozedur oder einer SQL-Anweisung zurückgegebenen Resultset zurückgeben oder indem Sie das RowUpdated
-Ereignis des DataAdapter
verwenden, um eine weitere SELECT-Anweisung auszuführen. Weitere Informationen und ein Beispiel finden Sie unter Abrufen von Identity- oder Autonumber-Werten.
Sortieren von Einfügungen, Updates und Löschungen
In vielen Fällen ist die Reihenfolge, in der die am DataSet
vorgenommenen Änderungen zur Datenquelle gesendet werden, sehr wichtig. Wenn beispielsweise ein Primärschlüsselwert für eine vorhandene Zeile aktualisiert und eine neue Zeile mit dem neuen Primärschlüsselwert als Fremdschlüssel hinzugefügt wurde, muss das Update vor der Einfügung verarbeitet werden.
Mithilfe der Select
-Methode der DataTable
können Sie ein DataRow
-Array zurückgeben, das nur auf Zeilen mit einem bestimmten RowState
verweist. Anschließend können Sie das zurückgegebene DataRow
-Array an die Update
-Methode des DataAdapter
übergeben, damit die geänderten Zeilen verarbeitet werden. Wenn Sie eine Teilmenge von Zeilen angeben, die aktualisiert werden sollen, können Sie die Reihenfolge steuern, in der Einfügungen, Updates und Löschvorgänge verarbeitet werden.
Beispiel
Durch den folgenden Code wird beispielsweise sichergestellt, dass die gelöschten Zeilen der Tabelle zuerst verarbeitet werden, anschließend die aktualisierten Zeilen und dann die eingefügten Zeilen.
// Assumes that dataSet and adapter are valid objects.
DataTable table = dataSet.Tables["Customers"];
// First process deletes.
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));
// Next process updates.
adapter.Update(table.Select(null, null,
DataViewRowState.ModifiedCurrent));
// Finally, process inserts.
adapter.Update(table.Select(null, null, DataViewRowState.Added));
Verwenden einer DataAdapter-Klasse zum Abrufen und Aktualisieren von Daten
Sie können DataAdapter verwenden, um die Daten abzurufen und zu aktualisieren.
Im Beispiel wird
DataAdapter.AcceptChangesDuringFill
verwendet, um die Daten in der Datenbank zu klonen. Wenn die Eigenschaft auf false festgelegt ist, wird AcceptChanges beim Ausfüllen der Tabelle nicht aufgerufen, und die neu hinzugefügten Zeilen werden als eingefügte Zeilen behandelt. Daher werden im Beispiel diese Zeilen zum Einfügen der neuen Zeilen in die Datenbank verwendet.Im Beispiel wird
DataAdapter.TableMappings
verwendet, um die Zuordnung zwischen der Quelltabelle und der DataTable-Klasse zu definieren.Darüber hinaus wird im Beispiel
DataAdapter.FillLoadOption
verwendet, um festzulegen, wie der Adapter die DataTable-Klasse aus der DbDataReader-Klasse füllt. Wenn Sie eine DataTable-Klasse erstellen, können Sie die Daten aus der Datenbank nur in die aktuelle Version oder die ursprüngliche Version schreiben, indem Sie die Eigenschaft auf LoadOption.Upsert oder LoadOption.PreserveChanges festlegen.Außerdem wird im Beispiel die Tabelle aktualisiert, indem
DbDataAdapter.UpdateBatchSize
zum Ausführen von Batchvorgängen verwendet wird.
Bevor Sie dieses Beispiel kompilieren und ausführen, müssen Sie die Beispieldatenbank erstellen:
USE [master]
GO
CREATE DATABASE [MySchool]
GO
USE [MySchool]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Course]([CourseID] [nvarchar](10) NOT NULL,
[Year] [smallint] NOT NULL,
[Title] [nvarchar](100) NOT NULL,
[Credits] [int] NOT NULL,
[DepartmentID] [int] NOT NULL,
CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED
(
[CourseID] ASC,
[Year] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Department]([DepartmentID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Budget] [money] NOT NULL,
[StartDate] [datetime] NOT NULL,
[Administrator] [int] NULL,
CONSTRAINT [PK_Department] PRIMARY KEY CLUSTERED
(
[DepartmentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]
GO
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1045', 2012, N'Calculus', 4, 7)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1061', 2012, N'Physics', 4, 1)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2021', 2012, N'Composition', 3, 2)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2042', 2012, N'Literature', 4, 2)
SET IDENTITY_INSERT [dbo].[Department] ON
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (1, N'Engineering', 350000.0000, CAST(0x0000999C00000000 AS DateTime), 2)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (2, N'English', 120000.0000, CAST(0x0000999C00000000 AS DateTime), 6)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (4, N'Economics', 200000.0000, CAST(0x0000999C00000000 AS DateTime), 4)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (7, N'Mathematics', 250024.0000, CAST(0x0000999C00000000 AS DateTime), 3)
SET IDENTITY_INSERT [dbo].[Department] OFF
ALTER TABLE [dbo].[Course] WITH CHECK ADD CONSTRAINT [FK_Course_Department] FOREIGN KEY([DepartmentID])
REFERENCES [dbo].[Department] ([DepartmentID])
GO
ALTER TABLE [dbo].[Course] CHECK CONSTRAINT [FK_Course_Department]
GO
using System;
using System.Data;
using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Linq;
using CSDataAdapterOperations.Properties;
class Program
{
static void Main(string[] args)
{
Settings settings = new Settings();
// Copy the data from the database. Get the table Department and Course from the database.
String selectString = @"SELECT [DepartmentID],[Name],[Budget],[StartDate],[Administrator]
FROM [MySchool].[dbo].[Department];
SELECT [CourseID],@Year as [Year],Max([Title]) as [Title],
Max([Credits]) as [Credits],Max([DepartmentID]) as [DepartmentID]
FROM [MySchool].[dbo].[Course]
Group by [CourseID]";
DataSet mySchool = new DataSet();
SqlCommand selectCommand = new SqlCommand(selectString);
SqlParameter parameter = selectCommand.Parameters.Add("@Year", SqlDbType.SmallInt, 2);
parameter.Value = new Random(DateTime.Now.Millisecond).Next(9999);
// Use DataTableMapping to map the source tables and the destination tables.
DataTableMapping[] tableMappings = { new DataTableMapping("Table", "Department"), new DataTableMapping("Table1", "Course") };
CopyData(mySchool, settings.MySchoolConnectionString, selectCommand, tableMappings);
Console.WriteLine("The following tables are from the database.");
foreach (DataTable table in mySchool.Tables)
{
Console.WriteLine(table.TableName);
ShowDataTable(table);
}
// Roll back the changes
DataTable department = mySchool.Tables["Department"];
DataTable course = mySchool.Tables["Course"];
department.Rows[0]["Name"] = "New" + department.Rows[0][1];
course.Rows[0]["Title"] = "New" + course.Rows[0]["Title"];
course.Rows[0]["Credits"] = 10;
Console.WriteLine("After we changed the tables:");
foreach (DataTable table in mySchool.Tables)
{
Console.WriteLine(table.TableName);
ShowDataTable(table);
}
department.RejectChanges();
Console.WriteLine("After use the RejectChanges method in Department table to roll back the changes:");
ShowDataTable(department);
DataColumn[] primaryColumns = { course.Columns["CourseID"] };
DataColumn[] resetColumns = { course.Columns["Title"] };
ResetCourse(course, settings.MySchoolConnectionString, primaryColumns, resetColumns);
Console.WriteLine("After use the ResetCourse method in Course table to roll back the changes:");
ShowDataTable(course);
// Batch update the table.
String insertString = @"Insert into [MySchool].[dbo].[Course]([CourseID],[Year],[Title],
[Credits],[DepartmentID])
values (@CourseID,@Year,@Title,@Credits,@DepartmentID)";
SqlCommand insertCommand = new SqlCommand(insertString);
insertCommand.Parameters.Add("@CourseID", SqlDbType.NVarChar, 10, "CourseID");
insertCommand.Parameters.Add("@Year", SqlDbType.SmallInt, 2, "Year");
insertCommand.Parameters.Add("@Title", SqlDbType.NVarChar, 100, "Title");
insertCommand.Parameters.Add("@Credits", SqlDbType.Int, 4, "Credits");
insertCommand.Parameters.Add("@DepartmentID", SqlDbType.Int, 4, "DepartmentID");
const Int32 batchSize = 10;
BatchInsertUpdate(course, settings.MySchoolConnectionString, insertCommand, batchSize);
}
private static void CopyData(DataSet dataSet, String connectionString, SqlCommand selectCommand, DataTableMapping[] tableMappings)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
selectCommand.Connection = connection;
connection.Open();
using (SqlDataAdapter adapter = new SqlDataAdapter(selectCommand))
{
adapter.TableMappings.AddRange(tableMappings);
// If set the AcceptChangesDuringFill as the false, AcceptChanges will not be called on a
// DataRow after it is added to the DataTable during any of the Fill operations.
adapter.AcceptChangesDuringFill = false;
adapter.Fill(dataSet);
}
}
}
// Roll back only one column or several columns data of the Course table by call ResetDataTable method.
private static void ResetCourse(DataTable table, String connectionString,
DataColumn[] primaryColumns, DataColumn[] resetColumns)
{
table.PrimaryKey = primaryColumns;
// Build the query string
String primaryCols = String.Join(",", primaryColumns.Select(col => col.ColumnName));
String resetCols = String.Join(",", resetColumns.Select(col => $"Max({col.ColumnName}) as {col.ColumnName}"));
String selectString = $"Select {primaryCols},{resetCols} from Course Group by {primaryCols}";
SqlCommand selectCommand = new SqlCommand(selectString);
ResetDataTable(table, connectionString, selectCommand);
}
// RejectChanges will roll back all changes made to the table since it was loaded, or the last time AcceptChanges
// was called. When you copy from the database, you can lose all the data after calling RejectChanges
// The ResetDataTable method rolls back one or more columns of data.
private static void ResetDataTable(DataTable table, String connectionString,
SqlCommand selectCommand)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
selectCommand.Connection = connection;
connection.Open();
using (SqlDataAdapter adapter = new SqlDataAdapter(selectCommand))
{
// The incoming values for this row will be written to the current version of each
// column. The original version of each column's data will not be changed.
adapter.FillLoadOption = LoadOption.Upsert;
adapter.Fill(table);
}
}
}
private static void BatchInsertUpdate(DataTable table, String connectionString,
SqlCommand insertCommand, Int32 batchSize)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
insertCommand.Connection = connection;
// When setting UpdateBatchSize to a value other than 1, all the commands
// associated with the SqlDataAdapter have to have their UpdatedRowSource
// property set to None or OutputParameters. An exception is thrown otherwise.
insertCommand.UpdatedRowSource = UpdateRowSource.None;
connection.Open();
using (SqlDataAdapter adapter = new SqlDataAdapter())
{
adapter.InsertCommand = insertCommand;
// Gets or sets the number of rows that are processed in each round-trip to the server.
// Setting it to 1 disables batch updates, as rows are sent one at a time.
adapter.UpdateBatchSize = batchSize;
adapter.Update(table);
Console.WriteLine("Successfully to update the table.");
}
}
}
private static void ShowDataTable(DataTable table)
{
foreach (DataColumn col in table.Columns)
{
Console.Write("{0,-14}", col.ColumnName);
}
Console.WriteLine("{0,-14}", "RowState");
foreach (DataRow row in table.Rows)
{
foreach (DataColumn col in table.Columns)
{
if (col.DataType.Equals(typeof(DateTime)))
Console.Write("{0,-14:d}", row[col]);
else if (col.DataType.Equals(typeof(Decimal)))
Console.Write("{0,-14:C}", row[col]);
else
Console.Write("{0,-14}", row[col]);
}
Console.WriteLine("{0,-14}", row.RowState);
}
}
}
namespace CSDataAdapterOperations.Properties
{
internal sealed partial class Settings : System.Configuration.ApplicationSettingsBase
{
private static readonly Settings defaultInstance =
((Settings)(System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default => defaultInstance;
[System.Configuration.ApplicationScopedSetting()]
[System.Configuration.DefaultSettingValue("Data Source=(local);Initial Catalog=MySchool;Integrated Security=True")]
public string MySchoolConnectionString => ((string)(this["MySchoolConnectionString"]));
}
}