Identitás vagy számértékek beolvasása
A relációs adatbázisok elsődleges kulcsa olyan oszlopok vagy oszlopok kombinációja, amelyek mindig egyedi értékeket tartalmaznak. Az elsődleges kulcs értékének ismeretével megkeresheti az azt tartalmazó sort. Az olyan relációs adatbázismotorok, mint az SQL Server, az Oracle és a Microsoft Access/Jet, támogatják az elsődleges kulcsként kijelölhető automatikusan növekvő oszlopok létrehozását. Ezeket az értékeket a kiszolgáló hozza létre, amikor sorokat ad hozzá egy táblához. Az SQL Serverben egy oszlop identitástulajdonságát állítja be, az Oracle-ben létrehoz egy sorozatot, a Microsoft Accessben pedig egy Számláló oszlopot.
A DataColumn tulajdonság igaz értékre állításával AutoIncrement automatikusan növekményes értékeket is létrehozhat. Ha azonban több ügyfélalkalmazás egymástól függetlenül hoz létre automatikusan növekvő értékeket, előfordulhat, hogy duplikált értékek jelennek meg egy DataTableadott példányban. Ha a kiszolgáló automatikusan növekményes értékeket hoz létre, azzal kiküszöböli a lehetséges ütközéseket, mivel lehetővé teszi, hogy minden felhasználó lekérje az egyes beszúrt sorok generált értékét.
A metódus meghívása DataAdapter
során az Update
adatbázis kimeneti paraméterekként vagy az IN Standard kiadás RT utasítással egy kötegben végrehajtott Standard kiadás LECT-utasítás eredményhalmazának első visszaadott rekordjaként küldheti vissza az adatokat az ADO.NET alkalmazásnak. ADO.NET lekérheti ezeket az értékeket, és frissítheti a megfelelő oszlopokat a DataRow frissítés során.
Egyes adatbázismotorok, például a Microsoft Access Jet adatbázismotor nem támogatják a kimeneti paramétereket, és nem tudnak több utasítást feldolgozni egyetlen kötegben. A Jet-adatbázismotor használatakor lekérheti a beszúrt sorhoz létrehozott új számlálóértéket, ha egy külön Standard kiadás LECT parancsot hajt végre egy eseménykezelőben az RowUpdated
DataAdapter
esemény eseményéhez.
Feljegyzés
Az automatikus növekményes érték másik alternatíva, ha egy NewGuidGuid objektum metódusával létrehoz egy GUID azonosítót vagy globálisan egyedi azonosítót az ügyfélszámítógépen, amely minden új sor beszúrásakor átmásolható a kiszolgálóra. A NewGuid
metódus egy 16 bájtos bináris értéket hoz létre, amely egy algoritmussal jön létre, amely nagy valószínűséggel biztosítja, hogy egyetlen érték sem lesz duplikálva. Egy SQL Server-adatbázisban a GUID egy oszlopban uniqueidentifier
van tárolva, amelyet az SQL Server automatikusan létrehozhat a Transact-SQL NEWID()
függvény használatával. A GUID elsődleges kulcsként való használata hátrányosan befolyásolhatja a teljesítményt. Az SQL Server támogatja a NEWSEQUENTIALID()
függvényt, amely szekvenciális GUID-t hoz létre, amely nem garantáltan globálisan egyedi, de hatékonyabban indexelhető.
SQL Server-identitásoszlop értékeinek beolvasása
A Microsoft SQL Server használatakor létrehozhat egy tárolt eljárást egy kimeneti paraméterrel a beszúrt sorok identitásértékének visszaadásához. Az alábbi táblázat az SQL Server három Transact-SQL-függvényét ismerteti, amelyek az identitásoszlop értékeinek lekérésére használhatók.
Függvény | Leírás |
---|---|
SCOPE_IDENTITY | Az aktuális végrehajtási hatókörben lévő utolsó identitásértéket adja vissza. SCOPE_IDENTITY a legtöbb forgatókönyv esetében ajánlott. |
@@IDENTITY | Az aktuális munkamenet bármely táblájában létrehozott utolsó identitásértéket tartalmazza. @@IDENTITY az eseményindítók befolyásolhatják, és előfordulhat, hogy nem a várt identitásértéket adja vissza. |
IDENT_CURRENT | Egy adott táblához létrehozott utolsó identitásértéket adja vissza bármely munkamenetben és hatókörben. |
Az alábbi tárolt eljárás bemutatja, hogyan szúrhat be egy sort a Kategóriák táblába, és hogyan használhat kimeneti paramétert a Transact-SQL SCOPE_IDENTITY() függvény által létrehozott új identitásérték visszaadásához.
CREATE PROCEDURE dbo.InsertCategory
@CategoryName nvarchar(15),
@Identity int OUT
AS
INSERT INTO Categories (CategoryName) VALUES(@CategoryName)
SET @Identity = SCOPE_IDENTITY()
A tárolt eljárás ezután megadható egy objektum forrásaként InsertCommandSqlDataAdapter . A CommandType tulajdonságnak a InsertCommand következőre kell állítania: StoredProcedure. Az identitáskimenet lekéréséhez hozzon létre egy SqlParameter olyant, amely a következőből áll ParameterDirectionOutput: . A feldolgozás során a InsertCommand
rendszer visszaadja az automatikusan növekményes identitásértéket, és az aktuális sor CategoryID oszlopába helyezi, ha a UpdatedRowSource beszúrási parancs tulajdonságát a következőre UpdateRowSource.OutputParameters
vagy értékre UpdateRowSource.Both
állítja.
Ha a beszúrási parancs egy IN Standard kiadás RT utasítást és egy Standard kiadás LECT utasítást is tartalmazó köteget hajt végre, amely az új identitásértéket adja vissza, akkor a beszúrási parancs UpdateRowSource.FirstReturnedRecord
tulajdonságának beállításával UpdatedRowSource
lekérheti az új értéket.
static void RetrieveIdentity(string connectionString)
{
using (SqlConnection connection =
new(connectionString))
{
// Create a SqlDataAdapter based on a SELECT query.
SqlDataAdapter adapter =
new(
"SELECT CategoryID, CategoryName FROM dbo.Categories",
connection)
{
//Create the SqlCommand to execute the stored procedure.
InsertCommand = new SqlCommand("dbo.InsertCategory",
connection)
{
CommandType = CommandType.StoredProcedure
}
};
// Add the parameter for the CategoryName. Specifying the
// ParameterDirection for an input parameter is not required.
adapter.InsertCommand.Parameters.Add(
new SqlParameter("@CategoryName", SqlDbType.NVarChar, 15,
"CategoryName"));
// Add the SqlParameter to retrieve the new identity value.
// Specify the ParameterDirection as Output.
SqlParameter parameter =
adapter.InsertCommand.Parameters.Add(
"@Identity", SqlDbType.Int, 0, "CategoryID");
parameter.Direction = ParameterDirection.Output;
// Create a DataTable and fill it.
DataTable categories = new();
adapter.Fill(categories);
// Add a new row.
DataRow newRow = categories.NewRow();
newRow["CategoryName"] = "New Category";
categories.Rows.Add(newRow);
adapter.Update(categories);
Console.WriteLine("List All Rows:");
foreach (DataRow row in categories.Rows)
{
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
}
}
}
Private Sub RetrieveIdentity(ByVal connectionString As String)
Using connection As SqlConnection = New SqlConnection( _
connectionString)
' Create a SqlDataAdapter based on a SELECT query.
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
"SELECT CategoryID, CategoryName FROM dbo.Categories", _
connection)
' Create the SqlCommand to execute the stored procedure.
adapter.InsertCommand = New SqlCommand("dbo.InsertCategory", _
connection)
adapter.InsertCommand.CommandType = CommandType.StoredProcedure
' Add the parameter for the CategoryName. Specifying the
' ParameterDirection for an input parameter is not required.
adapter.InsertCommand.Parameters.Add( _
"@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")
' Add the SqlParameter to retrieve the new identity value.
' Specify the ParameterDirection as Output.
Dim parameter As SqlParameter = _
adapter.InsertCommand.Parameters.Add( _
"@Identity", SqlDbType.Int, 0, "CategoryID")
parameter.Direction = ParameterDirection.Output
' Create a DataTable and fill it.
Dim categories As DataTable = New DataTable
adapter.Fill(categories)
' Add a new row.
Dim newRow As DataRow = categories.NewRow()
newRow("CategoryName") = "New Category"
categories.Rows.Add(newRow)
' Update the database.
adapter.Update(categories)
Console.WriteLine("List All Rows:")
Dim row As DataRow
For Each row In categories.Rows
Console.WriteLine("{0}: {1}", row(0), row(1))
Next
End Using
End Sub
Új identitásértékek egyesítése
Gyakori forgatókönyv, hogy meghívja a GetChanges
metódust DataTable
egy olyan másolat létrehozására, amely csak módosított sorokat tartalmaz, és az új példányt használja egy Update
DataAdapter
metódus meghívásakor. Ez különösen akkor hasznos, ha a módosított sorokat külön összetevőre kell helyeznie, amely végrehajtja a frissítést. A frissítést követően a másolat új identitásértékeket tartalmazhat, amelyeket ezután vissza kell vonni az eredetibe DataTable
. Az új identitásértékek valószínűleg eltérnek a DataTable
. Az egyesítés végrehajtásához meg kell őrizni a másolat autoIncrement oszlopainak eredeti értékeit, hogy az új identitásértékeket tartalmazó új sorok hozzáfűzése helyett meg lehessen keresni és frissíteni a meglévő sorokat az eredetiben DataTable
. Alapértelmezés szerint azonban ezek az eredeti értékek elvesznek egy metódus meghívása Update
DataAdapter
után, mert AcceptChanges
az implicit módon meghívódik minden egyes frissítetthez DataRow
.
A frissítés során kétféleképpen őrizheti meg egy adott fájl eredeti értékeit DataColumn
DataRow
DataAdapter
:
Az eredeti értékek megőrzésének első módszere a
AcceptChangesDuringUpdate
tulajdonság beállítása.DataAdapter
false
Ez mindenDataRow
frissítésreDataTable
hatással van. További információ és példakód: AcceptChangesDuringUpdate.A második módszer a kód írása az
RowUpdated
eseménykezelőben aDataAdapter
következő értékre való beállításhozSkipCurrentRowStatus: . AzDataRow
érték frissül, de az eredeti érték megmaradDataColumn
. Ez a módszer lehetővé teszi, hogy bizonyos sorok eredeti értékeit megőrizze, mások számára nem. A kód például megőrizheti a hozzáadott sorok eredeti értékeit, a szerkesztett vagy törölt sorok esetében pedig nem. Ehhez először ellenőrizze a StatementType kódot, majd csak a következő sorokat.StatusSkipCurrentRowStatementType
Insert
Ha ezek közül a módszerek közül bármelyiket használja egy DataRow
frissítés során DataAdapter
az eredeti értékek megőrzésére, ADO.NET műveletsorozatot hajt végre, hogy a kimeneti paraméterek vagy az eredményhalmaz első visszaadott sora által visszaadott új értékekre állítsa az aktuális értékeket DataRow
, miközben továbbra is megőrzi az eredeti értéket mindegyikben DataColumn
. Először az AcceptChanges
aktuális értékek eredeti értékként való megőrzésére hívjuk meg a DataRow
metódust, majd az új értékeket rendeljük hozzá. Ezeket a műveleteket követve azok a tulajdonságok, DataRows
amelyeknek a tulajdonsága be van RowState állítva, a tulajdonságuk RowState
a következőre lesz állítva AddedModified, ami váratlan lehet.
A parancsok eredményeinek az egyes DataRow frissítésekre való alkalmazásának módját az UpdatedRowSource egyes DbCommandparancsok tulajdonsága határozza meg. Ez a tulajdonság az enumerálásból származó UpdateRowSource
értékre van állítva.
Az alábbi táblázat azt ismerteti, hogy az UpdateRowSource
enumerálási értékek hogyan befolyásolják a RowState frissített sorok tulajdonságát.
Tag neve | Leírás |
---|---|
Both | AcceptChanges a rendszer meghívja, és a kimeneti paraméter értékei és/vagy a visszaadott eredményhalmaz első sorában lévő értékek is a DataRow frissítés alatt vannak. Ha nincsenek alkalmazandó értékek, akkor a következő leszUnchanged: RowState . |
FirstReturnedRecord | Ha egy sort ad vissza, a rendszer meghívja, AcceptChanges és a sor a módosított sorra van megfeleltetve a DataTable következőre Modified állítvaRowState : . Ha nem ad vissza sort, akkor AcceptChanges nem lesz meghívva, és a függvény megmarad RowState Added . |
None | A visszaadott paraméterek vagy sorok figyelmen kívül lesznek hagyva. Nincs hívás, AcceptChanges és a RowState maradványok Added . |
OutputParameters | AcceptChanges a rendszer meghívja, és a kimeneti paraméterek a módosított sorra vannak leképezve a DataTable következőre Modified állítvaRowState : . Ha nincsenek kimeneti paraméterek, a rendszer a RowState következő lesz Unchanged : . |
Példa
Ez a példa bemutatja, hogy a módosított sorok kinyerése egy DataTable
adott adatból, valamint az SqlDataAdapter adatforrás frissítése és egy új identitásoszlop értékének lekérése. A InsertCommand rendszer két Transact-SQL-utasítást hajt végre, az első az IN Standard kiadás RT utasítás, a második pedig egy Standard kiadás LECT utasítás, amely az identitásérték lekéréséhez a SCOPE_IDENTITY függvényt használja.
INSERT INTO dbo.Shippers (CompanyName)
VALUES (@CompanyName);
SELECT ShipperID, CompanyName FROM dbo.Shippers
WHERE ShipperID = SCOPE_IDENTITY();
A UpdatedRowSource
beszúrási parancs tulajdonsága a következőre UpdateRowSource.FirstReturnedRow
van állítva, a MissingSchemaAction tulajdonsága DataAdapter
pedig a következőre MissingSchemaAction.AddWithKey
van állítva: . A DataTable
ki van töltve, és a kód új sort ad hozzá a DataTable
. A módosított sorok ezután ki lesznek nyerve egy újba DataTable
, amelyet a rendszer átad a DataAdapter
kiszolgálónak, majd frissíti a kiszolgálót.
static void MergeIdentityColumns(string connectionString)
{
using (SqlConnection connection =
new(connectionString))
{
// Create the DataAdapter
SqlDataAdapter adapter =
new(
"SELECT ShipperID, CompanyName FROM dbo.Shippers",
connection)
{
//Add the InsertCommand to retrieve new identity value.
InsertCommand = new SqlCommand(
"INSERT INTO dbo.Shippers (CompanyName) " +
"VALUES (@CompanyName); " +
"SELECT ShipperID, CompanyName FROM dbo.Shippers " +
"WHERE ShipperID = SCOPE_IDENTITY();", connection)
};
// Add the parameter for the inserted value.
adapter.InsertCommand.Parameters.Add(
new SqlParameter("@CompanyName", SqlDbType.NVarChar, 40,
"CompanyName"));
adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both;
// MissingSchemaAction adds any missing schema to
// the DataTable, including identity columns
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
// Fill the DataTable.
DataTable shipper = new();
adapter.Fill(shipper);
// Add a new shipper.
DataRow newRow = shipper.NewRow();
newRow["CompanyName"] = "New Shipper";
shipper.Rows.Add(newRow);
// Add changed rows to a new DataTable. This
// DataTable will be used by the DataAdapter.
DataTable dataChanges = shipper.GetChanges()!;
// Add the event handler.
adapter.RowUpdated +=
OnRowUpdated;
adapter.Update(dataChanges);
connection.Close();
// Merge the updates.
shipper.Merge(dataChanges);
// Commit the changes.
shipper.AcceptChanges();
Console.WriteLine("Rows after merge.");
foreach (DataRow row in shipper.Rows)
{
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
}
}
}
Private Sub MergeIdentityColumns(ByVal connectionString As String)
Using connection As SqlConnection = New SqlConnection( _
connectionString)
' Create the DataAdapter
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
"SELECT ShipperID, CompanyName FROM dbo.Shippers", connection)
' Add the InsertCommand to retrieve new identity value.
adapter.InsertCommand = New SqlCommand( _
"INSERT INTO dbo.Shippers (CompanyName) " & _
"VALUES (@CompanyName); " & _
"SELECT ShipperID, CompanyName FROM dbo.Shippers " & _
"WHERE ShipperID = SCOPE_IDENTITY();", _
connection)
' Add the parameter for the inserted value.
adapter.InsertCommand.Parameters.Add( _
New SqlParameter("@CompanyName", SqlDbType.NVarChar, 40, _
"CompanyName"))
adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both
' MissingSchemaAction adds any missing schema to
' the DataTable, including identity columns
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
' Fill the DataTable.
Dim shipper As New DataTable
adapter.Fill(shipper)
' Add a new shipper.
Dim newRow As DataRow = shipper.NewRow()
newRow("CompanyName") = "New Shipper"
shipper.Rows.Add(newRow)
' Add changed rows to a new DataTable. This
' DataTable will be used by the DataAdapter.
Dim dataChanges As DataTable = shipper.GetChanges()
' Add the event handler.
AddHandler adapter.RowUpdated, New _
SqlRowUpdatedEventHandler(AddressOf OnRowUpdated)
' Update the datasource with the modified records.
adapter.Update(dataChanges)
' Merge the two DataTables.
shipper.Merge(dataChanges)
' Commit the changes.
shipper.AcceptChanges()
Console.WriteLine("Rows after merge.")
Dim row As DataRow
For Each row In shipper.Rows
Console.WriteLine("{0}: {1}", row(0), row(1))
Next
End Using
End Sub
Az OnRowUpdated
eseménykezelő ellenőrzi a StatementType sorokat SqlRowUpdatedEventArgs annak megállapításához, hogy a sor beszúrás-e. Ha igen, akkor a Status tulajdonság értéke SkipCurrentRow. A sor frissül, de a sor eredeti értékei megmaradnak. Az eljárás fő törzsében a Merge metódus az új identitás értékének az eredetibe DataTable
való egyesítése, végül AcceptChanges
pedig a meghívása.
protected static void OnRowUpdated(
object sender, SqlRowUpdatedEventArgs e)
{
// If this is an insert, then skip this row.
if (e.StatementType == StatementType.Insert)
{
e.Status = UpdateStatus.SkipCurrentRow;
}
}
Private Sub OnRowUpdated( _
ByVal sender As Object, ByVal e As SqlRowUpdatedEventArgs)
' If this is an insert, then skip this row.
If e.StatementType = StatementType.Insert Then
e.Status = UpdateStatus.SkipCurrentRow
End If
End Sub
A Microsoft Access számlálóértékek beolvasása
Ez a szakasz egy mintát tartalmaz, amely bemutatja, hogyan kérhetők le Autonumber
értékek a Jet 4.0-adatbázisból. A Jet-adatbázismotor nem támogatja több utasítás végrehajtását egy kötegben vagy a kimeneti paraméterek használatát, ezért ezen technikák egyikével sem lehet visszaadni a beszúrt sorhoz rendelt új Autonumber
értéket. Az új Autonumber
érték lekéréséhez azonban hozzáadhat kódot az RowUpdated
eseménykezelőhöz, amely egy külön Standard kiadás LECT @@IDENTITY utasítást hajt végre.
Példa
A sémainformációk hozzáadása MissingSchemaAction.AddWithKey
helyett ez a példa konfigurálja DataTable
a megfelelő sémát, mielőtt meghívja a OleDbDataAdapterDataTable
kitöltéshez. Ebben az esetben a CategoryID oszlop úgy van konfigurálva, hogy nullától kezdődően a beszúrt sorokhoz rendelt értéket nulláról AutoIncrementSeedAutoIncrementtrue
nullára, 0-ra és AutoIncrementStep -1-re állítsa. A kód ezután két új sort ad hozzá, és GetChanges
a módosított sorokat hozzáadja a metódusnak átadott újhoz DataTable
Update
.
static OleDbConnection s_connection = default!;
static void MergeIdentityColumns(OleDbConnection connection)
{
using (connection)
{
// Create a DataAdapter based on a SELECT query.
OleDbDataAdapter adapter = new(
"SELECT CategoryID, CategoryName FROM Categories",
connection)
{
// Create the INSERT command for the new category.
InsertCommand = new OleDbCommand(
"INSERT INTO Categories (CategoryName) Values(?)", connection)
{
CommandType = CommandType.Text
}
};
// Add the parameter for the CategoryName.
adapter.InsertCommand.Parameters.Add(
"@CategoryName", OleDbType.VarWChar, 15, "CategoryName");
adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both;
// Create a DataTable
DataTable categories = new();
// Create the CategoryID column and set its auto
// incrementing properties to decrement from zero.
DataColumn catId = new()
{
DataType = Type.GetType("System.Int32"),
ColumnName = "CategoryID",
AutoIncrement = true,
AutoIncrementSeed = 0,
AutoIncrementStep = -1
};
categories.Columns.Add(catId);
// Create the CategoryName column.
categories.Columns.Add(new DataColumn
{
DataType = Type.GetType("System.String"),
ColumnName = "CategoryName"
});
// Set the primary key on CategoryID.
var pKey = new DataColumn[] { catId };
categories.PrimaryKey = pKey;
// Fetch the data and fill the DataTable
adapter.Fill(categories);
// Add a new row.
DataRow newRow = categories.NewRow();
newRow["CategoryName"] = "New Category";
categories.Rows.Add(newRow);
// Add another new row.
DataRow newRow2 = categories.NewRow();
newRow2["CategoryName"] = "Another New Category";
categories.Rows.Add(newRow2);
// Add changed rows to a new DataTable that will be
// used to post the inserts to the database.
DataTable dataChanges = categories.GetChanges()!;
// Include an event to fill in the Autonumber value.
adapter.RowUpdated +=
OnRowUpdated;
// Update the database, inserting the new rows.
adapter.Update(dataChanges);
Console.WriteLine("Rows before merge:");
foreach (DataRow row in categories.Rows)
{
{
Console.WriteLine(" {0}: {1}", row[0], row[1]);
}
}
// Merge the two DataTables.
categories.Merge(dataChanges);
// Commit the changes.
categories.AcceptChanges();
Console.WriteLine("Rows after merge:");
foreach (DataRow row in categories.Rows)
{
{
Console.WriteLine(" {0}: {1}", row[0], row[1]);
}
}
}
}
Shared connection As OleDbConnection = Nothing
Private Shared Sub MergeIdentityColumns(ByVal connection As OleDbConnection)
Using connection
' Create a DataAdapter based on a SELECT query.
Dim adapter As OleDbDataAdapter = New OleDbDataAdapter( _
"SELECT CategoryID, CategoryName FROM Categories", _
connection)
' Create the INSERT command for the new category.
adapter.InsertCommand = New OleDbCommand( _
"INSERT INTO Categories (CategoryName) Values(?)", connection)
adapter.InsertCommand.CommandType = CommandType.Text
' Add the parameter for the CategoryName.
adapter.InsertCommand.Parameters.Add( _
"@CategoryName", OleDbType.VarWChar, 15, "CategoryName")
adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both
' Create a DataTable.
Dim categories As DataTable = New DataTable
' Create the CategoryID column and set its auto
' incrementing properties to decrement from zero.
Dim column As New DataColumn()
column.DataType = System.Type.GetType("System.Int32")
column.ColumnName = "CategoryID"
column.AutoIncrement = True
column.AutoIncrementSeed = 0
column.AutoIncrementStep = -1
categories.Columns.Add(column)
' Create the CategoryName column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "CategoryName"
categories.Columns.Add(column)
' Set the primary key on CategoryID.
Dim pKey(0) As DataColumn
pKey(0) = categories.Columns("CategoryID")
categories.PrimaryKey = pKey
' Fetch the data and fill the DataTable.
adapter.Fill(categories)
' Add a new row.
Dim newRow As DataRow = categories.NewRow()
newRow("CategoryName") = "New Category"
categories.Rows.Add(newRow)
' Add another new row.
Dim newRow2 As DataRow = categories.NewRow()
newRow2("CategoryName") = "Another New Category"
categories.Rows.Add(newRow2)
' Add changed rows to a new DataTable that will be
' used to post the inserts to the database.
Dim dataChanges As DataTable = categories.GetChanges()
' Include an event to fill in the Autonumber value.
AddHandler adapter.RowUpdated, _
New OleDbRowUpdatedEventHandler(AddressOf OnRowUpdated)
' Update the database, inserting the new rows.
adapter.Update(dataChanges)
Console.WriteLine("Rows before merge:")
Dim row1 As DataRow
For Each row1 In categories.Rows
Console.WriteLine(" {0}: {1}", row1(0), row1(1))
Next
' Merge the two DataTables.
categories.Merge(dataChanges)
' Commit the changes.
categories.AcceptChanges()
Console.WriteLine("Rows after merge:")
Dim row As DataRow
For Each row In categories.Rows
Console.WriteLine(" {0}: {1}", row(0), row(1))
Next
End Using
End Sub
Az RowUpdated
eseménykezelő ugyanazt a nyitottat OleDbConnection használja, mint a Update
OleDbDataAdapter
. Ellenőrzi a StatementType
OleDbRowUpdatedEventArgs beszúrt sorokat. Minden beszúrt sorhoz létrejön egy újOleDbCommand, amely végrehajtja a Standard kiadás LECT @@IDENTITY utasítást a kapcsolaton, és visszaadja az új Autonumber
értéket, amely a CategoryID oszlopba kerül.DataRow
A Status
tulajdonság ezután úgy van beállítva, hogy UpdateStatus.SkipCurrentRow
letiltsa a rejtett hívást.AcceptChanges
Az eljárás törzsében a metódus a Merge
két DataTable
objektum egyesítése, végül AcceptChanges
pedig a meghívás.
static void OnRowUpdated(
object sender, OleDbRowUpdatedEventArgs e)
{
// Conditionally execute this code block on inserts only.
if (e.StatementType == StatementType.Insert)
{
OleDbCommand cmdNewID = new("SELECT @@IDENTITY",
s_connection);
// Retrieve the Autonumber and store it in the CategoryID column.
e.Row["CategoryID"] = (int)cmdNewID.ExecuteScalar()!;
e.Status = UpdateStatus.SkipCurrentRow;
}
}
Private Shared Sub OnRowUpdated( _
ByVal sender As Object, ByVal e As OleDbRowUpdatedEventArgs)
' Conditionally execute this code block on inserts only.
If e.StatementType = StatementType.Insert Then
' Retrieve the Autonumber and store it in the CategoryID column.
Dim cmdNewID As New OleDbCommand("SELECT @@IDENTITY", _
connection)
e.Row("CategoryID") = CInt(cmdNewID.ExecuteScalar)
e.Status = UpdateStatus.SkipCurrentRow
End If
End Sub
Identitásértékek beolvasása
Gyakran identitásként állítjuk be az oszlopot, ha az oszlop értékeinek egyedinek kell lenniük. És néha szükségünk van az új adatok identitásértékére. Ez a minta bemutatja, hogyan lehet lekérni az identitásértékeket:
Tárolt eljárást hoz létre adatok beszúrásához és identitásérték visszaadásához.
Végrehajt egy parancsot az új adatok beszúrásához és az eredmény megjelenítéséhez.
Új adatok beszúrására és az eredmény megjelenítésére használ SqlDataAdapter .
A minta fordítása és futtatása előtt létre kell hoznia a mintaadatbázist a következő szkript használatával:
USE [master]
GO
CREATE DATABASE [MySchool]
GO
USE [MySchool]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE procedure [dbo].[CourseExtInfo] @CourseId int
as
select c.CourseID,c.Title,c.Credits,d.Name as DepartmentName
from Course as c left outer join Department as d on c.DepartmentID=d.DepartmentID
where c.CourseID=@CourseId
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create procedure [dbo].[DepartmentInfo] @DepartmentId int,@CourseCount int output
as
select @CourseCount=Count(c.CourseID)
from course as c
where c.DepartmentID=@DepartmentId
select d.DepartmentID,d.Name,d.Budget,d.StartDate,d.Administrator
from Department as d
where d.DepartmentID=@DepartmentId
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create PROCEDURE [dbo].[GetDepartmentsOfSpecifiedYear]
@Year int,@BudgetSum money output
AS
BEGIN
SELECT @BudgetSum=SUM([Budget])
FROM [MySchool].[dbo].[Department]
Where YEAR([StartDate])=@Year
SELECT [DepartmentID]
,[Name]
,[Budget]
,[StartDate]
,[Administrator]
FROM [MySchool].[dbo].[Department]
Where YEAR([StartDate])=@Year
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GradeOfStudent]
-- Add the parameters for the stored procedure here
@CourseTitle nvarchar(100),@FirstName nvarchar(50),
@LastName nvarchar(50),@Grade decimal(3,2) output
AS
BEGIN
select @Grade=Max(Grade)
from [dbo].[StudentGrade] as s join [dbo].[Course] as c on
s.CourseID=c.CourseID join [dbo].[Person] as p on s.StudentID=p.PersonID
where c.Title=@CourseTitle and p.FirstName=@FirstName
and p.LastName= @LastName
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[InsertPerson]
-- Add the parameters for the stored procedure here
@FirstName nvarchar(50),@LastName nvarchar(50),
@PersonID int output
AS
BEGIN
insert [dbo].[Person](LastName,FirstName) Values(@LastName,@FirstName)
set @PersonID=SCOPE_IDENTITY()
END
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
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Person]([PersonID] [int] IDENTITY(1,1) NOT NULL,
[LastName] [nvarchar](50) NOT NULL,
[FirstName] [nvarchar](50) NOT NULL,
[HireDate] [datetime] NULL,
[EnrollmentDate] [datetime] NULL,
[Picture] [varbinary](max) NULL,
CONSTRAINT [PK_School.Student] PRIMARY KEY CLUSTERED
(
[PersonID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[StudentGrade]([EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
[CourseID] [nvarchar](10) NOT NULL,
[StudentID] [int] NOT NULL,
[Grade] [decimal](3, 2) NOT NULL,
CONSTRAINT [PK_StudentGrade] PRIMARY KEY CLUSTERED
(
[EnrollmentID] 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 view [dbo].[EnglishCourse]
as
select c.CourseID,c.Title,c.Credits,c.DepartmentID
from Course as c join Department as d on c.DepartmentID=d.DepartmentID
where d.Name=N'English'
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
SET IDENTITY_INSERT [dbo].[Person] ON
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (1, N'Hu', N'Nan', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (2, N'Norman', N'Laura', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (3, N'Olivotto', N'Nino', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (4, N'Anand', N'Arturo', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (5, N'Jai', N'Damien', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (6, N'Holt', N'Roger', CAST(0x000097F100000000 AS DateTime), NULL)
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (7, N'Martin', N'Randall', CAST(0x00008B1A00000000 AS DateTime), NULL)
SET IDENTITY_INSERT [dbo].[Person] OFF
SET IDENTITY_INSERT [dbo].[StudentGrade] ON
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (1, N'C1045', 1, CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (2, N'C1045', 2, CAST(3.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (3, N'C1045', 3, CAST(2.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (4, N'C1045', 4, CAST(4.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (5, N'C1045', 5, CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (6, N'C1061', 1, CAST(4.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (7, N'C1061', 3, CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (8, N'C1061', 4, CAST(2.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (9, N'C1061', 5, CAST(1.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (10, N'C2021', 1, CAST(2.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (11, N'C2021', 2, CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (12, N'C2021', 4, CAST(3.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (13, N'C2021', 5, CAST(3.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (14, N'C2042', 1, CAST(2.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (15, N'C2042', 2, CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (16, N'C2042', 3, CAST(4.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (17, N'C2042', 5, CAST(3.00 AS Decimal(3, 2)))
SET IDENTITY_INSERT [dbo].[StudentGrade] 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
ALTER TABLE [dbo].[StudentGrade] WITH CHECK ADD CONSTRAINT [FK_StudentGrade_Student] FOREIGN KEY([StudentID])
REFERENCES [dbo].[Person] ([PersonID])
GO
ALTER TABLE [dbo].[StudentGrade] CHECK CONSTRAINT [FK_StudentGrade_Student]
GO
A kódlista a következő:
Tipp.
A kódlista egy MySchool.mdb nevű Access-adatbázisfájlra hivatkozik. A MySchool.mdb az MSDN Kódtár archívumából töltheti le.
using System;
using System.Data;
using System.Data.OleDb;
using System.Data.SqlClient;
class Program {
static void Main(string[] args) {
String SqlDbConnectionString = "Data Source=(local);Initial Catalog=MySchool;Integrated Security=True;Asynchronous Processing=true;";
InsertPerson(SqlDbConnectionString, "Janice", "Galvin");
Console.WriteLine();
InsertPersonInAdapter(SqlDbConnectionString, "Peter", "Krebs");
Console.WriteLine();
String oledbConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=Database\\MySchool.mdb";
InsertPersonInJet4Database(oledbConnectionString, "Janice", "Galvin");
Console.WriteLine();
Console.WriteLine("Please press any key to exit.....");
Console.ReadKey();
}
// Using stored procedure to insert a new row and retrieve the identity value
static void InsertPerson(String connectionString, String firstName, String lastName) {
String commandText = "dbo.InsertPerson";
using (SqlConnection conn = new SqlConnection(connectionString)) {
using (SqlCommand cmd = new SqlCommand(commandText, conn)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@FirstName", firstName));
cmd.Parameters.Add(new SqlParameter("@LastName", lastName));
SqlParameter personId = new SqlParameter("@PersonID", SqlDbType.Int);
personId.Direction = ParameterDirection.Output;
cmd.Parameters.Add(personId);
conn.Open();
cmd.ExecuteNonQuery();
Console.WriteLine("Person Id of new person:{0}", personId.Value);
}
}
}
// Using stored procedure in adapter to insert new rows and update the identity value.
static void InsertPersonInAdapter(String connectionString, String firstName, String lastName) {
String commandText = "dbo.InsertPerson";
using (SqlConnection conn = new SqlConnection(connectionString)) {
SqlDataAdapter mySchool = new SqlDataAdapter("Select PersonID,FirstName,LastName from [dbo].[Person]", conn);
mySchool.InsertCommand = new SqlCommand(commandText, conn);
mySchool.InsertCommand.CommandType = CommandType.StoredProcedure;
mySchool.InsertCommand.Parameters.Add(
new SqlParameter("@FirstName", SqlDbType.NVarChar, 50, "FirstName"));
mySchool.InsertCommand.Parameters.Add(
new SqlParameter("@LastName", SqlDbType.NVarChar, 50, "LastName"));
SqlParameter personId = mySchool.InsertCommand.Parameters.Add(new SqlParameter("@PersonID", SqlDbType.Int, 0, "PersonID"));
personId.Direction = ParameterDirection.Output;
DataTable persons = new DataTable();
mySchool.Fill(persons);
DataRow newPerson = persons.NewRow();
newPerson["FirstName"] = firstName;
newPerson["LastName"] = lastName;
persons.Rows.Add(newPerson);
mySchool.Update(persons);
Console.WriteLine("Show all persons:");
ShowDataTable(persons, 14);
}
}
/// For a Jet 4.0 database, we need use the single statement and event handler to insert new rows and retrieve the identity value.
static void InsertPersonInJet4Database(String connectionString, String firstName, String lastName) {
String commandText = "Insert into Person(FirstName,LastName) Values(?,?)";
using (OleDbConnection conn = new OleDbConnection(connectionString)) {
OleDbDataAdapter mySchool = new OleDbDataAdapter("Select PersonID,FirstName,LastName from Person", conn);
// Create Insert Command
mySchool.InsertCommand = new OleDbCommand(commandText, conn);
mySchool.InsertCommand.CommandType = CommandType.Text;
mySchool.InsertCommand.Parameters.Add(new OleDbParameter("@FirstName", OleDbType.VarChar, 50, "FirstName"));
mySchool.InsertCommand.Parameters.Add(new OleDbParameter("@LastName", OleDbType.VarChar, 50, "LastName"));
mySchool.InsertCommand.UpdatedRowSource = UpdateRowSource.Both;
DataTable persons = CreatePersonsTable();
mySchool.Fill(persons);
DataRow newPerson = persons.NewRow();
newPerson["FirstName"] = firstName;
newPerson["LastName"] = lastName;
persons.Rows.Add(newPerson);
DataTable dataChanges = persons.GetChanges();
mySchool.RowUpdated += OnRowUpdated;
mySchool.Update(dataChanges);
Console.WriteLine("Data before merging:");
ShowDataTable(persons, 14);
Console.WriteLine();
persons.Merge(dataChanges);
persons.AcceptChanges();
Console.WriteLine("Data after merging");
ShowDataTable(persons, 14);
}
}
static void OnRowUpdated(object sender, OleDbRowUpdatedEventArgs e) {
if (e.StatementType == StatementType.Insert) {
// Retrieve the identity value
OleDbCommand cmdNewId = new OleDbCommand("Select @@IDENTITY", e.Command.Connection);
e.Row["PersonID"] = (Int32)cmdNewId.ExecuteScalar();
// After the status is changed, the original values in the row are preserved. And the
// Merge method will be called to merge the new identity value into the original DataTable.
e.Status = UpdateStatus.SkipCurrentRow;
}
}
// Create the Persons table before filling.
private static DataTable CreatePersonsTable() {
DataTable persons = new DataTable();
DataColumn personId = new DataColumn();
personId.DataType = Type.GetType("System.Int32");
personId.ColumnName = "PersonID";
personId.AutoIncrement = true;
personId.AutoIncrementSeed = 0;
personId.AutoIncrementStep = -1;
persons.Columns.Add(personId);
DataColumn firstName = new DataColumn();
firstName.DataType = Type.GetType("System.String");
firstName.ColumnName = "FirstName";
persons.Columns.Add(firstName);
DataColumn lastName = new DataColumn();
lastName.DataType = Type.GetType("System.String");
lastName.ColumnName = "LastName";
persons.Columns.Add(lastName);
DataColumn[] pkey = { personId };
persons.PrimaryKey = pkey;
return persons;
}
private static void ShowDataTable(DataTable table, Int32 length) {
foreach (DataColumn col in table.Columns) {
Console.Write("{0,-" + length + "}", col.ColumnName);
}
Console.WriteLine();
foreach (DataRow row in table.Rows) {
foreach (DataColumn col in table.Columns) {
if (col.DataType.Equals(typeof(DateTime)))
Console.Write("{0,-" + length + ":d}", row[col]);
else if (col.DataType.Equals(typeof(Decimal)))
Console.Write("{0,-" + length + ":C}", row[col]);
else
Console.Write("{0,-" + length + "}", row[col]);
}
Console.WriteLine();
}
}
}