Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Wanneer u entiteitsobjecten, zoals Klanten of Orders, serialiseert naar een client via een netwerk, worden deze entiteiten losgekoppeld van hun gegevenscontext. De gegevenscontext houdt de wijzigingen of koppelingen met andere objecten niet meer bij. Dit is geen probleem zolang de clients alleen de gegevens lezen. Het is ook relatief eenvoudig om clients in staat te stellen nieuwe rijen aan een database toe te voegen. Als uw toepassing echter vereist dat clients gegevens kunnen bijwerken of verwijderen, moet u de entiteiten koppelen aan een nieuwe gegevenscontext voordat u aanroept DataContext.SubmitChanges. Als u bovendien een optimistische gelijktijdigheidscontrole met oorspronkelijke waarden gebruikt, heeft u ook een manier nodig om de database zowel de oorspronkelijke entiteit als de gewijzigde entiteit te leveren. De Attach methoden zijn beschikbaar om u in staat te stellen entiteiten in een nieuwe gegevenscontext te plaatsen nadat ze zijn losgekoppeld.
Zelfs als u proxyobjecten serialiseert in plaats van de LINQ naar SQL-entiteiten, moet u nog steeds een entiteit maken op de gegevenstoegangslaag (DAL) en deze koppelen aan een nieuwe System.Data.Linq.DataContext, om de gegevens naar de database te verzenden.
LINQ naar SQL is volledig onverschillig over hoe entiteiten worden geserialiseerd. Zie voor meer informatie over het gebruik van de tools Object Relational Designer en SQLMetal om klassen te genereren die serializeerbaar zijn met behulp van Windows Communication Foundation (WCF) Hoe: Entiteiten serializeerbaar maken.
Notitie
Roep alleen de Attach methoden aan voor nieuwe of gedeserialiseerde entiteiten. De enige manier om een entiteit los te koppelen van de oorspronkelijke gegevenscontext, is dat deze moet worden geserialiseerd. Als u een niet-gekoppelde entiteit probeert te koppelen aan een nieuwe gegevenscontext en die entiteit nog steeds uitgestelde loaders uit de vorige gegevenscontext heeft, genereert LINQ naar SQL een uitzondering. Een entiteit met uitgestelde laadfuncties uit twee verschillende gegevenscontexten kan ongewenste resultaten veroorzaken wanneer u invoeg-, update- en verwijderbewerkingen op die entiteit uitvoert. Zie Uitgesteld versus Onmiddellijk laden voor meer informatie over uitgestelde laadfuncties.
Gegevens ophalen
Clientmethode-aanroep
In de volgende voorbeelden ziet u een voorbeeldmethode-aanroep naar de DAL vanuit een Windows Forms-client. In dit voorbeeld wordt de DAL geïmplementeerd als een Windows-servicebibliotheek:
Private Function GetProdsByCat_Click(ByVal sender As Object, ByVal e _
As EventArgs)
' Create the WCF client proxy.
Dim proxy As New NorthwindServiceReference.Service1Client
' Call the method on the service.
Dim products As NorthwindServiceReference.Product() = _
proxy.GetProductsByCategory(1)
' If the database uses original values for concurrency checks,
' the client needs to store them and pass them back to the
' middle tier along with the new values when updating data.
For Each v As NorthwindClient1.NorthwindServiceReference.Product _
In products
' Persist to a List(Of Product) declared at class scope.
' Additional change-tracking logic is the responsibility
' of the presentation tier and/or middle tier.
originalProducts.Add(v)
Next
' (Not shown) Bind the products list to a control
' and/or perform whatever processing is necessary.
End Function
private void GetProdsByCat_Click(object sender, EventArgs e)
{
// Create the WCF client proxy.
NorthwindServiceReference.Service1Client proxy =
new NorthwindClient.NorthwindServiceReference.Service1Client();
// Call the method on the service.
NorthwindServiceReference.Product[] products =
proxy.GetProductsByCategory(1);
// If the database uses original values for concurrency checks,
// the client needs to store them and pass them back to the
// middle tier along with the new values when updating data.
foreach (var v in products)
{
// Persist to a list<Product> declared at class scope.
// Additional change-tracking logic is the responsibility
// of the presentation tier and/or middle tier.
originalProducts.Add(v);
}
// (Not shown) Bind the products list to a control
// and/or perform whatever processing is necessary.
}
Implementatie van middelste laag
In het volgende voorbeeld ziet u een implementatie van de interfacemethode op de middelste laag. Hier volgen de twee belangrijkste punten die u moet noteren:
- De DataContext wordt gedeclareerd binnen de methodescope.
- De methode retourneert een IEnumerable verzameling van de werkelijke resultaten. De serializer voert de query uit om de resultaten terug te sturen naar de client-/presentatielaag. Als u de queryresultaten lokaal wilt openen op de middelste laag, kunt u de uitvoering afdwingen door de queryvariabele aan te roepen
ToListofToArrayop te geven. Vervolgens kunt u die lijst of matrix retourneren als eenIEnumerable.
Public Function GetProductsByCategory(ByVal categoryID As Integer) _
As IEnumerable(Of Product)
Dim db As New NorthwindClasses1DataContext(connectionString)
Dim productQuery = _
From prod In db.Products _
Where prod.CategoryID = categoryID _
Select prod
Return productQuery.AsEnumerable()
End Function
public IEnumerable<Product> GetProductsByCategory(int categoryID)
{
NorthwindClasses1DataContext db =
new NorthwindClasses1DataContext(connectionString);
IEnumerable<Product> productQuery =
from prod in db.Products
where prod.CategoryID == categoryID
select prod;
return productQuery.AsEnumerable();
}
Een exemplaar van een gegevenscontext moet een levensduur hebben van één 'werkeenheid'. In een losjes gekoppelde omgeving is een werkeenheid meestal klein, misschien één optimistische transactie, inclusief één aanroep naar SubmitChanges. Daarom wordt de gegevenscontext gemaakt en opgeheven binnen de reikwijdte van een methode. Als de werkeenheid aanroepen naar bedrijfsregelslogica bevat, wilt u over het algemeen het DataContext exemplaar voor die hele bewerking behouden. In ieder geval, zijn DataContext exemplaren niet bedoeld om lang te worden behouden voor willekeurige aantallen transacties.
Met deze methode worden productobjecten geretourneerd, maar niet de verzameling Order_Detail objecten die aan elk product zijn gekoppeld. Gebruik het DataLoadOptions object om dit standaardgedrag te wijzigen. Zie Procedure: Bepalen hoeveel gerelateerde gegevens worden opgehaald voor meer informatie.
Gegevens invoegen
Als u een nieuw object wilt invoegen, roept de presentatielaag alleen de relevante methode aan op de interface van de middelste laag en geeft het nieuwe object door dat moet worden ingevoegd. In sommige gevallen kan het efficiënter zijn voor de client om slechts enkele waarden door te geven en de middelste laag het volledige object te maken.
Implementatie van middelste laag
Op de middelste laag wordt een nieuw DataContext-object gecreëerd, het object wordt aan DataContext gekoppeld met behulp van de InsertOnSubmit-methode en ingevoegd wanneer SubmitChanges wordt aangeroepen. Uitzonderingen, callbacks en foutvoorwaarden kunnen net als in elk ander webservicescenario worden verwerkt.
' No call to Attach is necessary for inserts.
Public Sub InsertOrder(ByVal o As Order)
Dim db As New NorthwindClasses1DataContext(connectionString)
db.Orders.InsertOnSubmit(o)
' Exception handling not shown.
db.SubmitChanges()
End Sub
// No call to Attach is necessary for inserts.
public void InsertOrder(Order o)
{
NorthwindClasses1DataContext db = new NorthwindClasses1DataContext(connectionString);
db.Orders.InsertOnSubmit(o);
// Exception handling not shown.
db.SubmitChanges();
}
Gegevens verwijderen
Als u een bestaand object uit de database wilt verwijderen, roept de presentatielaag de relevante methode aan op de interface van de middelste laag en geeft u de kopie door die de oorspronkelijke waarden van het object bevat die moeten worden verwijderd.
Verwijderingsbewerkingen omvatten optimistische gelijktijdigheidscontroles en het object dat moet worden verwijderd, moet eerst worden gekoppeld aan de nieuwe gegevenscontext. In dit voorbeeld is de Boolean-parameter ingesteld op false om aan te geven dat het object geen tijdstempel (RowVersion) heeft. Als uw databasetabel tijdstempels genereert voor elke record, zijn gelijktijdigheidscontroles veel eenvoudiger, met name voor de client. Geef het oorspronkelijke of gewijzigde object door en stel de Boolean parameter in op true. In ieder geval is het in het middensegment doorgaans nodig om de ChangeConflictException op te vangen. Voor meer informatie over het afhandelen van optimistische gelijktijdigheidsconflicten, zie Optimistische gelijktijdigheid: Overzicht.
Wanneer u entiteiten met vreemde-sleutelbeperkingen voor gekoppelde tabellen verwijdert, moet u eerst alle objecten in de EntitySet<TEntity> verzamelingen verwijderen.
' Attach is necessary for deletes.
Public Sub DeleteOrder(ByVal order As Order)
Dim db As New NorthwindClasses1DataContext(connectionString)
db.Orders.Attach(order, False)
' This will throw an exception if the order has order details.
db.Orders.DeleteOnSubmit(order)
Try
' ConflictMode is an optional parameter.
db.SubmitChanges(ConflictMode.ContinueOnConflict)
Catch ex As ChangeConflictException
' Get conflict information, and take actions
' that are appropriate for your application.
' See MSDN Article "How to: Manage Change
' Conflicts (LINQ to SQL).
End Try
End Sub
// Attach is necessary for deletes.
public void DeleteOrder(Order order)
{
NorthwindClasses1DataContext db = new NorthwindClasses1DataContext(connectionString);
db.Orders.Attach(order, false);
// This will throw an exception if the order has order details.
db.Orders.DeleteOnSubmit(order);
try
{
// ConflictMode is an optional parameter.
db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException e)
{
// Get conflict information, and take actions
// that are appropriate for your application.
// See MSDN Article How to: Manage Change Conflicts (LINQ to SQL).
}
}
Gegevens bijwerken
LINQ naar SQL ondersteunt updates in deze scenario's met optimistische gelijktijdigheid:
- Optimistische gelijktijdigheid op basis van tijdstempels of RowVersion-getallen.
- Optimistische gelijktijdigheid op basis van oorspronkelijke waarden van een subset van entiteitseigenschappen.
- Optimistische gelijktijdigheid uitgaande van de volledige oorspronkelijke en gewijzigde entiteiten.
U kunt ook updates of verwijderingen uitvoeren op een entiteit samen met de bijbehorende relaties, bijvoorbeeld een klant en een verzameling bijbehorende orderobjecten. Wanneer u wijzigingen aanbrengt op de client in een grafiek met entiteitsobjecten en hun onderliggende (EntitySet) verzamelingen, en de optimistische gelijktijdigheidscontroles oorspronkelijke waarden vereisen, moet de client die oorspronkelijke waarden opgeven voor elke entiteit en EntitySet<TEntity> elk object. Als u clients in staat wilt stellen een set gerelateerde updates, verwijderingen en invoegingen te maken in één methode-aanroep, moet u de client een manier bieden om aan te geven welk type bewerking moet worden uitgevoerd op elke entiteit. Op de middelste laag moet u vervolgens de juiste Attach methode aanroepen en vervolgens InsertOnSubmit, DeleteAllOnSubmitof InsertOnSubmit (zonder Attach, voor invoegingen) voor elke entiteit voordat u aanroept SubmitChanges. Haal geen gegevens op uit de database als een manier om oorspronkelijke waarden te verkrijgen voordat u updates probeert uit te voeren.
Voor meer informatie over optimistische gelijktijdigheid, zie Optimistische gelijktijdigheid: Overzicht. Zie How to: Manage Change Conflicts (Wijzigingenconflicten beheren) voor gedetailleerde informatie over het oplossen van optimistische gelijktijdigheidswijzigingsconflicten.
In de volgende voorbeelden ziet u elk scenario:
Optimistische gelijktijdigheid met tijdstempels
' Assume that "customer" has been sent by client.
' Attach with "true" to say this is a modified entity
' and it can be checked for optimistic concurrency
' because it has a column that is marked with the
' "RowVersion" attribute.
db.Customers.Attach(customer, True)
Try
' Optional: Specify a ConflictMode value
' in call to SubmitChanges.
db.SubmitChanges()
Catch ex As ChangeConflictException
' Handle conflict based on options provided.
' See MSDN article "How to: Manage Change
' Conflicts (LINQ to SQL)".
End Try
// Assume that "customer" has been sent by client.
// Attach with "true" to say this is a modified entity
// and it can be checked for optimistic concurrency because
// it has a column that is marked with "RowVersion" attribute
db.Customers.Attach(customer, true)
try
{
// Optional: Specify a ConflictMode value
// in call to SubmitChanges.
db.SubmitChanges();
}
catch(ChangeConflictException e)
{
// Handle conflict based on options provided
// See MSDN article How to: Manage Change Conflicts (LINQ to SQL).
}
Met een subset van de oorspronkelijke waarden
In deze benadering retourneert de client het volledige geserialiseerde object, samen met de waarden die moeten worden gewijzigd.
Public Sub UpdateProductInventory(ByVal p As Product, ByVal _
unitsInStock As Short?, ByVal unitsOnOrder As Short?)
Using db As New NorthwindClasses1DataContext(connectionString)
' p is the original unmodified product
' that was obtained from the database.
' The client kept a copy and returns it now.
db.Products.Attach(p, False)
' Now that the original values are in the data context,
' apply the changes.
p.UnitsInStock = unitsInStock
p.UnitsOnOrder = unitsOnOrder
Try
' Optional: Specify a ConflictMode value
' in call to SubmitChanges.
db.SubmitChanges()
Catch ex As Exception
' Handle conflict based on options provided.
' See MSDN article "How to: Manage Change Conflicts
' (LINQ to SQL)".
End Try
End Using
End Sub
public void UpdateProductInventory(Product p, short? unitsInStock, short? unitsOnOrder)
{
using (NorthwindClasses1DataContext db = new NorthwindClasses1DataContext(connectionString))
{
// p is the original unmodified product
// that was obtained from the database.
// The client kept a copy and returns it now.
db.Products.Attach(p, false);
// Now that the original values are in the data context, apply the changes.
p.UnitsInStock = unitsInStock;
p.UnitsOnOrder = unitsOnOrder;
try
{
// Optional: Specify a ConflictMode value
// in call to SubmitChanges.
db.SubmitChanges();
}
catch (ChangeConflictException e)
{
// Handle conflict based on provided options.
// See MSDN article How to: Manage Change Conflicts
// (LINQ to SQL).
}
}
}
Met volledige entiteiten
Public Sub UpdateProductInfo(ByVal newProd As Product, ByVal _
originalProd As Product)
Using db As New NorthwindClasses1DataContext(connectionString)
db.Products.Attach(newProd, originalProd)
Try
' Optional: Specify a ConflictMode value
' in call to SubmitChanges.
db.SubmitChanges()
Catch ex As Exception
' Handle potential change conflict in whatever way
' is appropriate for your application.
' For more information, see the MSDN article
' "How to: Manage Change Conflicts (LINQ to
' SQL)".
End Try
End Using
End Sub
public void UpdateProductInfo(Product newProd, Product originalProd)
{
using (NorthwindClasses1DataContext db = new
NorthwindClasses1DataContext(connectionString))
{
db.Products.Attach(newProd, originalProd);
try
{
// Optional: Specify a ConflictMode value
// in call to SubmitChanges.
db.SubmitChanges();
}
catch (ChangeConflictException e)
{
// Handle potential change conflict in whatever way
// is appropriate for your application.
// For more information, see the MSDN article
// How to: Manage Change Conflicts (LINQ to SQL)/
}
}
}
Roep AttachAll aan in plaats van Attach om een verzameling bij te werken.
Verwachte entiteitsleden
Zoals eerder vermeld, moeten alleen bepaalde leden van het entiteitsobject worden ingesteld voordat u de Attach methoden aanroept. Entiteitsleden die moeten worden ingesteld, moeten voldoen aan de volgende criteria:
- Maak deel uit van de identiteit van de entiteit.
- Naar verwachting zullen wijzigingen worden aangebracht.
- Wees een tijdstempel of zorg ervoor dat het UpdateCheck-attribuut op iets anders dan
Neveris ingesteld.
Als een tabel een tijdstempel of versienummer gebruikt voor een optimistische gelijktijdigheidscontrole, moet u deze leden instellen voordat u aanroept Attach. Een lid is toegewezen voor optimistische gelijktijdigheidscontrole wanneer de IsVersion eigenschap is ingesteld op 'true' op dat kolomkenmerk. Aangevraagde updates worden alleen verzonden als het versienummer of de tijdstempelwaarden hetzelfde zijn in de database.
Een lid wordt ook gebruikt in de optimistische gelijktijdigheidscontrole zolang het lid niet is UpdateCheck ingesteld op Never. De standaardwaarde is Always als er geen andere waarde is opgegeven.
Als een van deze vereiste leden ontbreekt, wordt een ChangeConflictException opgeworpen tijdens SubmitChanges ('Rij niet gevonden of gewijzigd').
Provincie
Nadat een entiteitsobject is gekoppeld aan het DataContext exemplaar, wordt het object beschouwd als de PossiblyModified status. Er zijn drie manieren om ervoor te zorgen dat een bijgevoegd object als Modified wordt beschouwd.
Voeg deze als ongewijzigd toe en wijzig de velden vervolgens rechtstreeks.
Koppel deze aan de Attach overbelasting die huidige en oorspronkelijke objectexemplaren gebruikt. Hiermee wordt de wijzigingstracker geleverd met oude en nieuwe waarden, zodat deze automatisch weet welke velden zijn gewijzigd.
Koppel deze met de Attach overload-functionaliteit die een tweede booleaanse parameter gebruikt (ingesteld op true). Dit vertelt de veranderingstracker dat het object als aangepast moet worden beschouwd zonder oorspronkelijke waarden op te geven. In deze benadering moet het object een versie-/tijdstempelveld hebben.
Zie Objectstatussen en Wijzigingen bijhouden voor meer informatie.
Als een entiteitsobject al voorkomt in de id-cache met dezelfde identiteit als het object dat wordt gekoppeld, wordt er een DuplicateKeyException gegenereerd.
Wanneer u bijvoegt met een IEnumerable set objecten, wordt er een DuplicateKeyException gegenereerd wanneer er een al bestaande sleutel aanwezig is. Resterende objecten zijn niet gekoppeld.