Recupero di dati e operazioni CUD in applicazioni a più livelli (LINQ to SQL)Data Retrieval and CUD Operations in N-Tier Applications (LINQ to SQL)

Quando si serializzano oggetti entità, ad esempio Customers o Orders, in un client di una rete, tali entità vengono disconnesse dal relativo contesto dati.When you serialize entity objects such as Customers or Orders to a client over a network, those entities are detached from their data context. Il contesto dati non rileva più le modifiche o le associazioni con gli altri oggetti,The data context no longer tracks their changes or their associations with other objects. il che non rappresenta un problema se i client leggono solo i dati.This is not an issue as long as the clients are only reading the data. È inoltre relativamente semplice consentire ai client di aggiungere nuove righe in un database.It is also relatively simple to enable clients to add new rows to a database. Tuttavia, se l'applicazione richiede che i client siano in grado di aggiornare o eliminare i dati, sarà necessario associare le entità a un nuovo contesto dati prima di chiamare DataContext.SubmitChanges.However, if your application requires that clients be able to update or delete data, then you must attach the entities to a new data context before you call DataContext.SubmitChanges. Inoltre, se si usa un controllo della concorrenza ottimistica con i valori originali, sarà necessario anche un modo per fornire al database l'entità originale e l'entità come modificata.In addition, if you are using an optimistic concurrency check with original values, then you will also need a way to provide the database both the original entity and the entity as modified. I metodi Attach vengono forniti per consentire l'inserimento delle entità in un nuovo contesto dati dopo essere stati disconnessi.The Attach methods are provided to enable you to put entities into a new data context after they have been detached.

Anche se si serializzano oggetti proxy al posto delle LINQ to SQLLINQ to SQL entità, è ancora necessario costruire un'entità nel livello di accesso ai dati (dal) e collegarla a un nuovo System.Data.Linq.DataContextper inviare i dati al database.Even if you are serializing proxy objects in place of the LINQ to SQLLINQ to SQL entities, you still have to construct an entity on the data access layer (DAL), and attach it to a new System.Data.Linq.DataContext, in order to submit the data to the database.

LINQ to SQLLINQ to SQLnon è completamente diverso dal modo in cui le entità vengono serializzate.is completely indifferent about how entities are serialized. Per ulteriori informazioni su come utilizzare gli strumenti Object Relational Designer e SQLMetal per generare classi serializzabili utilizzando Windows Communication Foundation (WCF), vedere procedura: Rendere serializzabilile entità.For more information about how to use the Object Relational Designer and SQLMetal tools to generate classes that are serializable by using Windows Communication Foundation (WCF), see How to: Make Entities Serializable.

Nota

Chiamare i metodi Attach solo sulle entità nuove o deserializzate.Only call the Attach methods on new or deserialized entities. L'unico modo per disconnettere un'entità dal contesto dati originali è serializzarla.The only way for an entity to be detached from its original data context is for it to be serialized. Se si tenta di associare un'entità disconnessa a un nuovo contesto dati e tale entità dispone ancora di caricatori posticipati dal contesto dati precedente, in LINQ to SQLLINQ to SQL verrà generata un'eccezione.If you try to attach an undetached entity to a new data context, and that entity still has deferred loaders from its previous data context, LINQ to SQLLINQ to SQL will thrown an exception. Un'entità con caricatori posticipati da due contesti di dati diversi può causare risultati indesiderati quando si eseguono operazioni di inserimento, aggiornamento ed eliminazione su tale entità.An entity with deferred loaders from two different data contexts could cause unwanted results when you perform insert, update, and delete operations on that entity. Per ulteriori informazioni sui caricatori posticipati, vedere caricamento posticipato rispetto al caricamento immediato.For more information about deferred loaders, see Deferred versus Immediate Loading.

Recupero dei datiRetrieving Data

Chiamata al metodo clientClient Method Call

Negli esempi seguenti viene illustrata una chiamata al metodo di esempio nel DAL da un client Windows Form.The following examples show a sample method call to the DAL from a Windows Forms client. In questo esempio il DAL viene implementato come libreria dei servizi Windows:In this example, the DAL is implemented as a Windows Service Library:

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.  
    }  

Implementazione del livello intermedioMiddle Tier Implementation

Nell'esempio seguente viene illustrata un'implementazione del metodo di interfaccia nel livello intermedio.The following example shows an implementation of the interface method on the middle tier. Di seguito sono riportati i due punti principali da tenere presente:The following are the two main points to note:

  • L'oggetto DataContext viene dichiarato nell'ambito del metodo.The DataContext is declared at method scope.

  • Il metodo restituisce una raccolta IEnumerable dei risultati effettivi.The method returns an IEnumerable collection of the actual results. Il serializzatore eseguirà la query per restituire i risultati a livello di client/presentazione.The serializer will execute the query to send the results back to the client/presentation tier. Per accedere localmente ai risultati della query nel livello intermedio, è possibile forzare l'esecuzione chiamando ToList o ToArray sulla variabile della query.To access the query results locally on the middle tier, you can force execution by calling ToList or ToArray on the query variable. È quindi possibile restituire tale elenco o matrice come oggetto IEnumerable.You can then return that list or array as an IEnumerable.

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();   
}  

Un'istanza di un contesto dati deve avere una durata di una "unità di lavoro."An instance of a data context should have a lifetime of one "unit of work." In un ambiente a regime di controllo libero ("loosely-coupled") un'unità di lavoro è tipicamente piccola, forse una transazione ottimistica, inclusa una singola chiamata a SubmitChanges.In a loosely-coupled environment, a unit of work is typically small, perhaps one optimistic transaction, including a single call to SubmitChanges. Pertanto, il contesto dati viene creato ed eliminato nell'ambito del metodo.Therefore, the data context is created and disposed at method scope. Se l'unità di lavoro include chiamate alla logica delle regole business, è preferibile in genere mantenere l'istanza DataContext per l'intera operazione.If the unit of work includes calls to business rules logic, then generally you will want to keep the DataContext instance for that whole operation. In ogni caso, le istanze DataContext non devono essere conservate per lunghi periodi di tempo con un numero arbitrario di transazioni.In any case, DataContext instances are not intended to be kept alive for long periods of time across arbitrary numbers of transactions.

Questo metodo restituirà oggetti Product ma non la raccolta di oggetti Order_Detail associati a ogni oggetto Product.This method will return Product objects but not the collection of Order_Detail objects that are associated with each Product. Usare l'oggetto DataLoadOptions per modificare questo comportamento predefinito.Use the DataLoadOptions object to change this default behavior. Per altre informazioni, vedere Procedura: Controllare la quantità di dati correlati recuperata.For more information, see How to: Control How Much Related Data Is Retrieved.

Inserimento di datiInserting Data

Per inserire un nuovo oggetto, il livello di presentazione chiama il metodo desiderato sull'interfaccia del livello intermedio e passa il nuovo oggetto da inserire.To insert a new object, the presentation tier just calls the relevant method on the middle tier interface, and passes in the new object to insert. In alcuni casi, può essere più efficiente per il client passare solo alcuni valori e far costruire al livello intermedio l'oggetto completo.In some cases, it may be more efficient for the client to pass in only some values and have the middle tier construct the full object.

Implementazione del livello intermedioMiddle Tier Implementation

Nel livello intermedio viene creato un nuovo oggetto DataContext, l'oggetto viene associato all'oggetto DataContext usando il metodo InsertOnSubmit e l'oggetto viene inserito quando viene chiamato il metodo SubmitChanges.On the middle tier, a new DataContext is created, the object is attached to the DataContext by using the InsertOnSubmit method, and the object is inserted when SubmitChanges is called. Le eccezioni, i callback e le condizioni di errore possono essere gestiti analogamente a qualsiasi altro scenario del servizio Web.Exceptions, callbacks, and error conditions can be handled just as in any other Web service scenario.

' 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();  
    }  

Eliminazione di datiDeleting Data

Per eliminare un oggetto esistente dal database, il livello di presentazione chiama il metodo desiderato sull'interfaccia del livello intermedio e passa la copia che include i valori originali dell'oggetto da eliminare.To delete an existing object from the database, the presentation tier calls the relevant method on the middle tier interface, and passes in its copy that includes original values of the object to be deleted.

Le operazioni di eliminazione implicano i controlli di concorrenza ottimistica e l'oggetto da eliminare deve prima essere associato al nuovo contesto dati.Delete operations involve optimistic concurrency checks, and the object to be deleted must first be attached to the new data context. In questo esempio il parametro Boolean è impostato su false per indicare che l'oggetto non ha un timestamp (RowVersion).In this example, the Boolean parameter is set to false to indicate that the object does not have a timestamp (RowVersion). Se la tabella di database genera timestamp per ogni record, i controlli di concorrenza sono molto più semplici, sopratutto per il client.If your database table does generate timestamps for each record, then concurrency checks are much simpler, especially for the client. È necessario solo passare l'oggetto originale o modificato e impostare il parametro Boolean su true.Just pass in either the original or modified object and set the Boolean parameter to true. In ogni caso, nel livello intermedio è in genere necessario rilevare l'eccezione ChangeConflictException.In any case, on the middle tier it is typically necessary to catch the ChangeConflictException. Per ulteriori informazioni su come gestire i conflitti di concorrenza ottimistica, vedere concorrenza ottimistica: Panoramica.For more information about how to handle optimistic concurrency conflicts, see Optimistic Concurrency: Overview.

Quando si eliminano le entità che hanno vincoli di chiave esterna nelle tabelle associate, è necessario prima eliminare tutti gli oggetti nelle raccolte EntitySet<TEntity>.When deleting entities that have foreign key constraints on associated tables, you must first delete all the objects in its EntitySet<TEntity> collections.

' 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).  
    }  
}  

Aggiornamento di datiUpdating Data

In LINQ to SQLLINQ to SQL sono supportati gli aggiornamenti di questi scenari relativi alla concorrenza ottimistica:LINQ to SQLLINQ to SQL supports updates in these scenarios involving optimistic concurrency:

  • Concorrenza ottimistica basata sui timestamp o i numeri RowVersion.Optimistic concurrency based on timestamps or RowVersion numbers.

  • Concorrenza ottimistica basata sui valori originali di un subset di proprietà dell'entità.Optimistic concurrency based on original values of a subset of entity properties.

  • Concorrenza ottimistica basata sulle entità complete originali o modificate.Optimistic concurrency based on the complete original and modified entities.

È inoltre possibile eseguire aggiornamenti o eliminazioni su un'entità con le relative relazioni, ad esempio un oggetto Customer e una raccolta degli oggetti Order associati.You can also perform updates or deletes on an entity together with its relations, for example a Customer and a collection of its associated Order objects. Quando nel client si effettuano modifiche a un grafico di oggetti entità e alle relative raccolte figlio (EntitySet) e i controlli di concorrenza ottimistica richiedono i valori originali, il client deve fornire tali valori originali per ogni entità e oggetto EntitySet<TEntity>.When you make modifications on the client to a graph of entity objects and their child (EntitySet) collections, and the optimistic concurrency checks require original values, the client must provide those original values for each entity and EntitySet<TEntity> object. Per consentire ai client di effettuare un set di aggiornamenti, eliminazioni e inserimenti correlati in una sola chiamata al metodo, è necessario fornire al client un modo per indicare il tipo di operazione da eseguire su ogni entità.If you want to enable clients to make a set of related updates, deletes, and insertions in a single method call, you must provide the client a way to indicate what type of operation to perform on each entity. Nel livello intermedio chiamare quindi il metodo Attach adatto e quindi InsertOnSubmit, DeleteAllOnSubmit o InsertOnSubmit (senza Attach per gli inserimenti) per ogni entità prima di chiamare SubmitChanges.On the middle tier, you then must call the appropriate Attach method and then InsertOnSubmit, DeleteAllOnSubmit, or InsertOnSubmit (without Attach, for insertions) for each entity before you call SubmitChanges. Non recuperare i dati dal database per ottenere i valori originali prima dell'esecuzione degli aggiornamenti.Do not retrieve data from the database as a way to obtain original values before you try updates.

Per ulteriori informazioni sulla concorrenza ottimistica, vedere concorrenza ottimistica: Panoramica.For more information about optimistic concurrency, see Optimistic Concurrency: Overview. Per informazioni dettagliate sulla risoluzione dei conflitti di modifica della concorrenza ottimistica, vedere procedura: Gestire i conflittidi modifica.For detailed information about resolving optimistic concurrency change conflicts, see How to: Manage Change Conflicts.

Negli esempi seguenti vengono illustrati tutti gli scenari:The following examples demonstrate each scenario:

Concorrenza ottimistica con timestampOptimistic concurrency with timestamps

' 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).  
}  

Con un subset di valori originaliWith Subset of Original Values

In questo approccio il client restituisce l'oggetto serializzato completo, insieme ai valori da modificare.In this approach, the client returns the complete serialized object, together with the values to be modified.

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).  
        }  
    }  
}  

Con entità completeWith Complete Entities

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 conflicgt 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)/  
        }   
    }  
}  

Per aggiornare una raccolta, chiamare AttachAll anziché Attach.To update a collection, call AttachAll instead of Attach.

Membri dell'entità previstiExpected Entity Members

Come indicato in precedenza, è necessario impostare solo alcuni membri dell'oggetto entità prima di chiamare i metodi Attach.As stated previously, only certain members of the entity object are required to be set before you call the Attach methods. I membri dell'entità da impostare devono soddisfare i criteri seguenti:Entity members that are required to be set must fulfill the following criteria:

  • Devono essere parte dell'identità dell'entità.Be part of the entity’s identity.

  • Devono poter essere modificati.Be expected to be modified.

  • Devono essere un timestamp o avere l'attributo UpdateCheck impostato su un valore diverso da Never.Be a timestamp or have its UpdateCheck attribute set to something besides Never.

Se una tabella usa un timestamp o un numero di versione per un controllo della concorrenza ottimistica, è necessario impostare tali membri prima di chiamare Attach.If a table uses a timestamp or version number for an optimistic concurrency check, you must set those members before you call Attach. Un membro è dedicato al controllo della concorrenza ottimistica quando la proprietà IsVersion è impostata su true nell'attributo Column.A member is dedicated for optimistic concurrency checking when the IsVersion property is set to true on that Column attribute. Tutti gli aggiornamenti necessari vengono inviati solo se i valori del numero di versione o del timestamp sono gli stessi di quelli presenti nel database.Any requested updates will be submitted only if the version number or timestamp values are the same on the database.

Un membro viene usato anche nel controllo della concorrenza ottimistica purché la proprietà del membro UpdateCheck non sia impostata su Never.A member is also used in the optimistic concurrency check as long as the member does not have UpdateCheck set to Never. Il valore predefinito è Always se non viene specificato un altro valore.The default value is Always if no other value is specified.

Se uno di questi membri necessari risulta mancante, viene generata un'eccezione ChangeConflictException durante l'operazione SubmitChanges ("Riga non trovata o modificata").If any one of these required members is missing, a ChangeConflictException is thrown during SubmitChanges ("Row not found or changed").

StatoState

Dopo aver associato un oggetto entità all'istanza DataContext, lo stato dell'oggetto diventa PossiblyModified.After an entity object is attached to the DataContext instance, the object is considered to be in the PossiblyModified state. Sono disponibili tre modalità per forzare un oggetto associato in modo da essere considerato Modified.There are three ways to force an attached object to be considered Modified.

  1. Associarlo come non modificato e quindi modificare direttamente i campi.Attach it as unmodified, and then directly modify the fields.

  2. Associarlo con l'overload Attach che accetta le istanze dell'oggetto originale e corrente.Attach it with the Attach overload that takes current and original object instances. In questo modo alla funzionalità di ricerca delle modifiche vengono forniti i valori vecchi e nuovi per rilevare automaticamente i campi modificati.This supplies the change tracker with old and new values so that it will automatically know which fields have changed.

  3. Associarlo con l'overload Attach che accetta un secondo parametro booleano (impostato su true).Attach it with the Attach overload that takes a second Boolean parameter (set to true). In questo modo la funzionalità di ricerca delle modifiche considererà l'oggetto modificato senza dover richiedere i valori originali.This will tell the change tracker to consider the object modified without having to supply any original values. In questo approccio l'oggetto deve avere un campo di versione/timestamp.In this approach, the object must have a version/timestamp field.

Per ulteriori informazioni, vedere Stati degli oggetti e rilevamento delle modifiche.For more information, see Object States and Change-Tracking.

Se un oggetto entità è già presente nella Cache ID con la stessa identità dell'oggetto associato, viene generata un'eccezione DuplicateKeyException.If an entity object already occurs in the ID Cache with the same identity as the object being attached, a DuplicateKeyException is thrown.

Quando si associa un set di oggetti IEnumerable, viene generata un'eccezione DuplicateKeyException se è presente una chiave già esistente.When you attach with an IEnumerable set of objects, a DuplicateKeyException is thrown when an already existing key is present. Gli oggetti rimanenti non verranno associati.Remaining objects are not attached.

Vedere ancheSee also