Sdílet prostřednictvím


Operace načítání dat a vytvoření, aktualizace a odstranění v N-úrovňových aplikacích (LINQ to SQL)

Při serializaci objektů entity, jako jsou Zákazníci nebo Objednávky do klienta přes síť, jsou tyto entity odpojeny od jejich datového kontextu. Kontext dat už neuslyší jejich změny nebo jejich přidružení s jinými objekty. Nejedná se o problém, pokud klienti čtou jenom data. Je také relativně jednoduché umožnit klientům přidávat do databáze nové řádky. Pokud však vaše aplikace vyžaduje, aby klienti mohli aktualizovat nebo odstranit data, musíte entity před voláním DataContext.SubmitChangespřipojit k novému kontextu dat . Kromě toho, pokud používáte optimistickou kontrolu souběžnosti s původními hodnotami, budete také potřebovat způsob, jak poskytnout databázi původní i entitu podle změny. K Attach dispozici jsou metody, které umožňují umístit entity do nového datového kontextu po jejich odpojení.

I když serializujete proxy objekty místo entit LINQ to SQL, stále musíte vytvořit entitu na vrstvě přístupu k datům (DAL) a připojit ho k nové System.Data.Linq.DataContext, aby bylo možné odeslat data do databáze.

LINQ to SQL je zcela nemyslí na to, jak jsou entity serializovány. Další informace o tom, jak používat nástroje Návrhář relací objektů a SQLMetal ke generování tříd, které jsou serializovatelné pomocí technologie Windows Communication Foundation (WCF), naleznete v tématu Postupy: Vytváření entit serializovatelné.

Poznámka:

Volejte Attach metody pouze u nových nebo deserializovaných entit. Jediný způsob, jak se entita odpojila od původního kontextu dat, je, aby byla serializována. Pokud se pokusíte připojit nepřipojenou entitu k novému kontextu dat a tato entita má stále odložené zavaděče z předchozího kontextu dat, linQ to SQL vyvolá výjimku. Entita s odloženými zavaděči ze dvou různých kontextů dat může způsobit nežádoucí výsledky při provádění operací vložení, aktualizace a odstranění dané entity. Další informace o odložených zavaděčích naleznete v tématu Deferred versus Okamžité načítání.

Načítání dat

Volání metody klienta

Následující příklady ukazují volání ukázkové metody dal z klienta model Windows Forms. V tomto příkladu se dal implementuje jako knihovna služeb systému Windows:

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

Implementace střední vrstvy

Následující příklad ukazuje implementaci metody rozhraní na střední vrstvě. Všimněte si těchto dvou hlavních bodů:

  • Je DataContext deklarován v oboru metody.

  • Metoda vrátí IEnumerable kolekci skutečných výsledků. Serializátor spustí dotaz, který odešle výsledky zpět do klientské nebo prezentační vrstvy. Pokud chcete získat přístup k výsledkům dotazu místně na střední úrovni, můžete vynutit spuštění voláním ToList nebo ToArray proměnnou dotazu. Pak můžete tento seznam nebo pole vrátit jako 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();
}  

Instance kontextu dat by měla mít životnost jedné "jednotky práce". V volně propojených prostředích je jednotka práce obvykle malá, možná jedna optimistická transakce, včetně jednoho volání SubmitChanges. Proto je kontext dat vytvořen a uvolněn v oboru metody. Pokud jednotka práce zahrnuje volání logiky obchodních pravidel, obecně budete chtít zachovat DataContext instanci pro celou operaci. V každém případě DataContext nejsou instance určeny k udržování naživu po dlouhou dobu napříč libovolnými čísly transakcí.

Tato metoda vrátí objekty Product, ale ne kolekci Order_Detail objektů, které jsou přidruženy k jednotlivým produktům. Pomocí objektu DataLoadOptions můžete toto výchozí chování změnit. Další informace naleznete v tématu Postupy: Řízení, kolik souvisejících dat se načte.

Vkládání dat

Pokud chcete vložit nový objekt, prezentační vrstva volá příslušnou metodu v rozhraní střední vrstvy a předá nový objekt, který se má vložit. V některýchpřípadechchm datům může být v některých případech efektivnější předat klientovi pouze některé hodnoty a

Implementace střední vrstvy

Na střední vrstvě se vytvoří nový DataContext objekt, který je připojen k objektu DataContext pomocí InsertOnSubmit metody, a objekt se vloží, když SubmitChanges je volána. Výjimky, zpětná volání a chybové podmínky je možné zpracovat stejně jako v jakémkoli jiném scénáři webové služby.

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

Odstranění dat

Chcete-li odstranit existující objekt z databáze, prezentační vrstva volá příslušnou metodu v rozhraní střední vrstvy a předává její kopii, která obsahuje původní hodnoty objektu, který se má odstranit.

Operace odstranění zahrnují kontroly optimistické souběžnosti a objekt, který se má odstranit, musí být nejprve připojen k novému kontextu dat. V tomto příkladu Boolean je parametr nastaven na false indikaci, že objekt nemá časové razítko (RowVersion). Pokud vaše databázová tabulka generuje časové razítka pro každý záznam, jsou kontroly souběžnosti mnohem jednodušší, zejména pro klienta. Stačí předat původní nebo upravený objekt a nastavit Boolean parametr na true. V každém případě je na střední úrovni obvykle nutné zachytit ChangeConflictException. Další informace o tom, jak zpracovávat konflikty optimistické souběžnosti, najdete v tématu Optimistická souběžnost: Přehled.

Při odstraňování entit, které mají omezení cizího klíče u přidružených tabulek, musíte nejprve odstranit všechny objekty v jejích EntitySet<TEntity> kolekcích.

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

Aktualizace dat

LINQ to SQL podporuje aktualizace v těchto scénářích zahrnujících optimistickou souběžnost:

  • Optimistická souběžnost založená na časových razítkech nebo číslech RowVersion.

  • Optimistická souběžnost založená na původních hodnotách podmnožina vlastností entity.

  • Optimistická souběžnost založená na kompletních původních a upravených entitách.

U entity můžete také provádět aktualizace nebo odstranění společně s jeho vztahy, například zákazník a kolekci přidružených objektů Objednávky. Když provedete úpravy klienta v grafu objektů entit a jejich podřízených kolekcí (EntitySet) a kontroly optimistické souběžnosti vyžadují původní hodnoty, klient musí poskytnout tyto původní hodnoty pro každou entitu a EntitySet<TEntity> objekt. Pokud chcete klientům povolit, aby vytvořili sadu souvisejících aktualizací, odstranění a vložení do jednoho volání metody, musíte klientovi poskytnout způsob, jak určit, jaký typ operace se má pro každou entitu provést. Na střední vrstvě pak musíte před voláním volat příslušnou Attach metodu a pak InsertOnSubmit, DeleteAllOnSubmitnebo InsertOnSubmit (bez Attach) pro každou entitu SubmitChanges. Než vyzkoušíte aktualizace, nenačítejte data z databáze jako způsob získání původních hodnot.

Další informace o optimistické souběžnosti najdete v tématu Optimistická souběžnost: Přehled. Podrobné informace o řešení konfliktů změn optimistické souběžnosti najdete v tématu Postupy: Správa konfliktů změn.

Následující příklady ukazují jednotlivé scénáře:

Optimistická souběžnost s časovými razítky

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

S podmnožinou původních hodnot

V tomto přístupu klient vrátí kompletní serializovaný objekt spolu s hodnotami, které se mají upravit.

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

S úplnými entitami

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

Chcete-li aktualizovat kolekci, místo volání AttachAllAttach.

Očekávané členy entity

Jak jsme uvedli dříve, před voláním Attach metod je nutné nastavit pouze určité členy objektu entity. Členové entity, které je potřeba nastavit, musí splňovat následující kritéria:

  • Buďte součástí identity entity.

  • Očekává se, že se změní.

  • Být časové razítko nebo mít jeho UpdateCheck atribut nastaven na něco kromě Never.

Pokud tabulka používá časové razítko nebo číslo verze pro optimistickou kontrolu souběžnosti, musíte tyto členy nastavit před voláním Attach. Člen je vyhrazen pro optimistickou souběžnost kontroly, když IsVersion je vlastnost nastavena na true u atributu Column. Všechny požadované aktualizace budou odeslány pouze v případě, že je v databázi stejné číslo verze nebo hodnoty časového razítka.

Člen se také používá v optimistické kontrole souběžnosti, pokud člen není UpdateCheck nastaven na Neverhodnotu . Výchozí hodnota je Always , pokud není zadána žádná jiná hodnota.

Pokud některý z těchto požadovaných členů chybí, ChangeConflictException vyvolá se během SubmitChanges operace (Řádek nebyl nalezen nebo změněn).

Stav

Po připojení objektu entity k DataContext instanci se objekt považuje za ve PossiblyModified stavu. Existují tři způsoby, jak vynutit, aby připojený objekt byl považován za .Modified

  1. Připojte ho jako nezměněné a upravte pole přímo.

  2. Připojte ho Attach s přetížením, které přebírá aktuální a původní instance objektů. Tento nástroj poskytuje sledování změn starými a novými hodnotami, aby automaticky věděl, která pole se změnila.

  3. Připojte ho Attach s přetížením, které přebírá druhý logický parametr (nastavený na hodnotu true). Tím nástroji Change Tracker řeknete, aby zvážil změněný objekt, aniž by musel zadávat žádné původní hodnoty. V tomto přístupu musí mít objekt pole verze/časového razítka.

Další informace naleznete v tématu Stavy objektů a Sledování změn.

Pokud se objekt entity již vyskytuje v mezipaměti ID se stejnou identitou jako připojený objekt, DuplicateKeyException vyvolá se chyba.

Když připojíte sadu IEnumerable objektů, DuplicateKeyException vyvolá se při přítomnosti již existujícího klíče. Zbývající objekty nejsou připojeny.

Viz také