Odłączone jednostkiDisconnected entities

Wystąpienie typu DbContext będzie automatycznie śledzić obiektów zwracanych z bazy danych.A DbContext instance will automatically track entities returned from the database. Zmiany wprowadzone do tych jednostek następnie zostanie wykryty, gdy SaveChanges nosi nazwę bazy danych zostaną zaktualizowane zgodnie z potrzebami.Changes made to these entities will then be detected when SaveChanges is called and the database will be updated as needed. Zobacz podstawowe Zapisz i powiązanych danych Aby uzyskać szczegółowe informacje.See Basic Save and Related Data for details.

Jednak czasami jednostki są wysyłane zapytanie przy użyciu jednego wystąpienia kontekstu i następnie zapisywane przy użyciu innego wystąpienia.However, sometimes entities are queried using one context instance and then saved using a different instance. To często zdarza się w scenariuszach "odłączonego", takich jak aplikacja sieci web, gdzie jednostki są badane, wysłane do klienta, modyfikować, wysyłanych z powrotem do serwera w żądaniu i następnie zapisany.This often happens in "disconnected" scenarios such as a web application where the entities are queried, sent to the client, modified, sent back to the server in a request, and then saved. W tym przypadku kontekstu drugiego wystąpienia musi wiedzieć, czy jednostki są nowe (powinien zostać wstawiony) lub istniejące (powinien zostać zaktualizowany).In this case, the second context instance needs to know whether the entities are new (should be inserted) or existing (should be updated).

Porada

Przykład użyty w tym artykule można zobaczyć w witrynie GitHub.You can view this article's sample on GitHub.

Porada

EF Core można śledzić tylko jedno wystąpienie jednostki z danej wartości klucza podstawowego.EF Core can only track one instance of any entity with a given primary key value. Najlepszym sposobem, aby uniknąć tego problemu jest do użycia krótkotrwałe kontekstu dla każdej jednostki pracy w taki sposób, że kontekst zaczyna się puste, zawiera jednostki podłączone do niego, zapisuje te jednostki oraz kontekst jest usunięty i odrzucone.The best way to avoid this being an issue is to use a short-lived context for each unit-of-work such that the context starts empty, has entities attached to it, saves those entities, and then the context is disposed and discarded.

Identyfikowanie nowych jednostekIdentifying new entities

Klient identyfikuje nowe jednostkiClient identifies new entities

Najprostszym przypadku radzenia sobie z jest, gdy klient informuje serwer, czy jednostka jest nowym lub istniejącym.The simplest case to deal with is when the client informs the server whether the entity is new or existing. Na przykład często żądania, aby wstawić nowy obiekt różni się od żądanie zaktualizowania istniejącej jednostki.For example, often the request to insert a new entity is different from the request to update an existing entity.

Dalszej części tej sekcji omówiono przypadki gdzie go, które są niezbędne określić w inny sposób, czy należy wstawić lub zaktualizować.The remainder of this section covers the cases where it necessary to determine in some other way whether to insert or update.

Za pomocą automatycznego generowania kluczyWith auto-generated keys

Wartość automatycznie generowanego klucza często może służyć do określenia, czy jednostka musi być wstawiane lub aktualizowane.The value of an automatically generated key can often be used to determine whether an entity needs to be inserted or updated. Jeśli nie ustawiono klucza (oznacza to, że nadal ma wartość domyślną CLR o wartości null, wartość zero, itp.), a jednostka musi być nowe musi wstawiania.If the key has not been set (that is, it still has the CLR default value of null, zero, etc.), then the entity must be new and needs inserting. Z drugiej strony Jeśli ustawiono wartość klucza, następnie go musi już zostały wcześniej zapisane i teraz wymaga aktualizacji.On the other hand, if the key value has been set, then it must have already been previously saved and now needs updating. Innymi słowy Jeśli klucz ma wartość, a następnie jednostki badano wysłane do klienta i ma teraz wróć do zaktualizowania.In other words, if the key has a value, then the entity was queried, sent to the client, and has now come back to be updated.

Jest łatwy do sprawdzenia nie ustawiono klucza, gdy znana jest typem jednostki:It is easy to check for an unset key when the entity type is known:

public static bool IsItNew(Blog blog) 
    => blog.BlogId == 0;

EF ma również wbudowane sposobem wykonania tego typu jednostki i typ klucza:However, EF also has a built-in way to do this for any entity type and key type:

public static bool IsItNew(DbContext context, object entity) 
    => !context.Entry(entity).IsKeySet;

Porada

Klucze są ustawione, tak szybko, jak jednostki są śledzone od kontekstu, nawet jeśli jednostka jest w stanie dodany.Keys are set as soon as entities are tracked by the context, even if the entity is in the Added state. Dzięki temu podczas przechodzenia między wykres jednostek i podejmowania decyzji o postępowaniu z każdego, na przykład, jak za pomocą interfejsu API TrackGraph.This helps when traversing a graph of entities and deciding what to do with each, such as when using the TrackGraph API. Wartość klucza powinna służyć wyłącznie w taki sposób, w tym miejscu pokazano przed wszelkie rozmowy do śledzenia jednostki.The key value should only be used in the way shown here before any call is made to track the entity.

Przy użyciu innych kluczyWith other keys

Niektóre inny mechanizm jest potrzebny do identyfikowania nowych jednostek, gdy wartości klucza nie są generowane automatycznie.Some other mechanism is needed to identify new entities when key values are not generated automatically. Istnieją dwa ogólne podejścia do tego:There are two general approaches to this:

  • Zapytanie dla jednostkiQuery for the entity
  • Przekazać flagę od klientaPass a flag from the client

Aby wysłać zapytanie do jednostki, po prostu użyj metody Find:To query for the entity, just use the Find method:

public static bool IsItNew(BloggingContext context, Blog blog)
    => context.Blogs.Find(blog.BlogId) == null;

Jest poza zakres tego dokumentu, aby wyświetlić pełny kod do przekazywania flagę od klienta.It is beyond the scope of this document to show the full code for passing a flag from a client. W aplikacji sieci web zwykle oznacza to, co innych żądań dla rozmaitych akcji lub przekazywanie pewnego stanu w żądaniu, a następnie wyodrębniania go w kontrolerze.In a web app, it usually means making different requests for different actions, or passing some state in the request then extracting it in the controller.

Zapisywanie pojedynczych jednostekSaving single entities

Jeśli wiadomo, czy jest potrzebny insert nebo update, a następnie dodaj lub zaktualizuj można odpowiednio:If it is known whether or not an insert or update is needed, then either Add or Update can be used appropriately:

public static void Insert(DbContext context, object entity)
{
    context.Add(entity);
    context.SaveChanges();
}

public static void Update(DbContext context, object entity)
{
    context.Update(entity);
    context.SaveChanges();
}

Jednak jeśli jednostki używa automatycznego generowania wartości klucza, następnie metoda aktualizacji może służyć w obu przypadkach:However, if the entity uses auto-generated key values, then the Update method can be used for both cases:

public static void InsertOrUpdate(DbContext context, object entity)
{
    context.Update(entity);
    context.SaveChanges();
}

Metoda aktualizacji zazwyczaj oznacza jednostkę do aktualizacji, wstawiania nie.The Update method normally marks the entity for update, not insert. Jednakże jeśli jednostka ma klucz wygenerowany automatycznie, a nie wartość klucza została ustawiona, a następnie jednostki zamiast tego jest automatycznie oznaczony do wstawienia.However, if the entity has a auto-generated key, and no key value has been set, then the entity is instead automatically marked for insert.

Porada

To zachowanie została wprowadzona w programie EF Core 2.0.This behavior was introduced in EF Core 2.0. Dla wcześniejszych wersji należy zawsze jawnie wybrać Dodawanie lub aktualizowanie.For earlier releases it is always necessary to explicitly choose either Add or Update.

Jeśli jednostka nie korzysta z automatycznego generowania kluczy, a następnie aplikacja musi zdecydować, czy wstawione lub zaktualizowane jednostki: na przykład:If the entity is not using auto-generated keys, then the application must decide whether the entity should be inserted or updated: For example:

public static void InsertOrUpdate(BloggingContext context, Blog blog)
{
    var existingBlog = context.Blogs.Find(blog.BlogId);
    if (existingBlog == null)
    {
        context.Add(blog);
    }
    else
    {
        context.Entry(existingBlog).CurrentValues.SetValues(blog);
    }

    context.SaveChanges();
}

Dostępne są następujące kroki:The steps here are:

  • Jeśli dodasz Znajdź zwraca wartość null, a następnie baza danych nie zawiera jeszcze blog o tym identyfikatorze, dlatego nazywamy Oznacz ją do wstawienia.If Find returns null, then the database doesn't already contain the blog with this ID, so we call Add mark it for insertion.
  • Jeśli wyszukiwanie zwraca jednostkę, następnie istnieje w bazie danych i kontekstu jest teraz śledzenie istniejącej jednostkiIf Find returns an entity, then it exists in the database and the context is now tracking the existing entity
    • Następnie używamy SetValues można ustawić wartości dla wszystkich właściwości dla tej jednostki do tych, które pochodzą od klienta.We then use SetValues to set the values for all properties on this entity to those that came from the client.
    • Wywołanie SetValues spowoduje oznaczenie jednostkę którą chcesz zaktualizować, zgodnie z potrzebami.The SetValues call will mark the entity to be updated as needed.

Porada

SetValues oznaczy tylko zmienione właściwości, które mają różne wartości do tych w jednostce śledzone.SetValues will only mark as modified the properties that have different values to those in the tracked entity. Oznacza to, że gdy aktualizacja jest wysyłana, tylko te kolumny, które rzeczywiście zostały zmienione zostaną zaktualizowane.This means that when the update is sent, only those columns that have actually changed will be updated. (I jeśli nic się nie zmieniło, aktualizacja nie zostanie wysłana w ogóle)(And if nothing has changed, then no update will be sent at all.)

Praca z wykresamiWorking with graphs

Rozwiązanie tożsamościIdentity resolution

Jak wspomniano powyżej, programem EF Core tylko śledzić jednego wystąpienia z danej wartości klucza podstawowego jednostki.As noted above, EF Core can only track one instance of any entity with a given primary key value. Pracując z wykresami wykres najlepiej powinny być tworzone, tak, aby ta niezmiennej jest utrzymywany i kontekst powinien być używany dla tylko jednej jednostki pracy.When working with graphs the graph should ideally be created such that this invariant is maintained, and the context should be used for only one unit-of-work. Jeśli wykres zawiera duplikaty, następnie będzie konieczne do przetworzenia na wykresie przed wysłaniem ich do programu EF w celu skonsolidowania wielu wystąpień w jednym.If the graph does contain duplicates, then it will be necessary to process the graph before sending it to EF to consolidate multiple instances into one. To może nie być prosta których wystąpienia mają wartościami będącymi w konflikcie i relacje, dlatego konsolidację duplikaty powinno się odbywać szybko, jak to możliwe w potoku aplikacji, aby uniknąć konfliktów.This may not be trivial where instances have conflicting values and relationships, so consolidating duplicates should be done as soon as possible in your application pipeline to avoid conflict resolution.

Wszystkie nowe/wszystkich istniejących jednostek.All new/all existing entities

Przykładem korzystania z wykresów jest wstawianie lub aktualizowania blogu wraz z jego kolekcja skojarzone wpisów.An example of working with graphs is inserting or updating a blog together with its collection of associated posts. Powinien zostać wstawiony wszystkich jednostek w wykresie lub wszystkie powinny być aktualizowane, następnie proces jest taka sama, jak opisano powyżej dla jednej jednostki.If all the entities in the graph should be inserted, or all should be updated, then the process is the same as described above for single entities. Na przykład wykres blogów i wpisów umieszczonych w następujący sposób:For example, a graph of blogs and posts created like this:

var blog = new Blog
{
    Url = "http://sample.com",
    Posts = new List<Post>
    {
        new Post {Title = "Post 1"},
        new Post {Title = "Post 2"},
    }
};

mogą być wstawiane w następujący sposób:can be inserted like this:

public static void InsertGraph(DbContext context, object rootEntity)
{
    context.Add(rootEntity);
    context.SaveChanges();
}

Spowoduje to oznaczenie blogu i wszystkie wpisy, które ma zostać wstawiony wywołania do Add.The call to Add will mark the blog and all the posts to be inserted.

Podobnie jeśli wszystkie jednostki w grafie muszą zostać zaktualizowane, wówczas aktualizacji mogą być używane:Likewise, if all the entities in a graph need to be updated, then Update can be used:

public static void UpdateGraph(DbContext context, object rootEntity)
{
    context.Update(rootEntity);
    context.SaveChanges();
}

Blog i wszystkie jego wpisy zostaną oznaczone do zaktualizowania.The blog and all its posts will be marked to be updated.

Kombinacja nowych i istniejących jednostekMix of new and existing entities

Za pomocą automatycznego generowania kluczy aktualizacja ponownie można zarówno dla operacji wstawienia i aktualizacje, nawet jeśli wykres zawiera różne jednostki, które wymagają, wstawianie i tych, które wymagają zaktualizowania:With auto-generated keys, Update can again be used for both inserts and updates, even if the graph contains a mix of entities that require inserting and those that require updating:

public static void InsertOrUpdateGraph(DbContext context, object rootEntity)
{
    context.Update(rootEntity);
    context.SaveChanges();
}

Aktualizacja spowoduje oznaczenie dowolnej jednostki w wykresu, blogu lub wpis do wstawienia nie zainstalowano zestawu wartości klucza, podczas gdy inne jednostki są oznaczone do aktualizacji.Update will mark any entity in the graph, blog or post, for insertion if it does not have a key value set, while all other entities are marked for update.

Jak wcześniej, bez korzystania z automatycznego generowania kluczy, zapytanie i jakieś operacje przetwarzania może być użyty:As before, when not using auto-generated keys, a query and some processing can be used:

public static void InsertOrUpdateGraph(BloggingContext context, Blog blog)
{
    var existingBlog = context.Blogs
        .Include(b => b.Posts)
        .FirstOrDefault(b => b.BlogId == blog.BlogId);

    if (existingBlog == null)
    {
        context.Add(blog);
    }
    else
    {
        context.Entry(existingBlog).CurrentValues.SetValues(blog);
        foreach (var post in blog.Posts)
        {
            var existingPost = existingBlog.Posts
                .FirstOrDefault(p => p.PostId == post.PostId);

            if (existingPost == null)
            {
                existingBlog.Posts.Add(post);
            }
            else
            {
                context.Entry(existingPost).CurrentValues.SetValues(post);
            }
        }
    }

    context.SaveChanges();
}

Obsługa usuwaHandling deletes

Delete mogą być trudne do obsługi, ponieważ często Brak jednostki oznacza, że go usunąć.Delete can be tricky to handle since often the absence of an entity means that it should be deleted. Jednym ze sposobów, aby poradzić sobie z tym jest używać "usuwania nietrwałego" w taki sposób, że jednostka jest oznaczony jako usunięty zamiast rzeczywistości usuwane.One way to deal with this is to use "soft deletes" such that the entity is marked as deleted rather than actually being deleted. Usuwa, a następnie staje się taka sama jak aktualizacje.Deletes then becomes the same as updates. Usuwanie nietrwałego może być implementowany w przy użyciu zapytania filtry.Soft deletes can be implemented in using query filters.

Usuwa wartość true, aby uzyskać wspólny wzorzec jest użycie rozszerzenia wzorca zapytania do wykonania, co to jest zasadniczo różnica wykresu Na przykład:For true deletes, a common pattern is to use an extension of the query pattern to perform what is essentially a graph diff. For example:

public static void InsertUpdateOrDeleteGraph(BloggingContext context, Blog blog)
{
    var existingBlog = context.Blogs
        .Include(b => b.Posts)
        .FirstOrDefault(b => b.BlogId == blog.BlogId);

    if (existingBlog == null)
    {
        context.Add(blog);
    }
    else
    {
        context.Entry(existingBlog).CurrentValues.SetValues(blog);
        foreach (var post in blog.Posts)
        {
            var existingPost = existingBlog.Posts
                .FirstOrDefault(p => p.PostId == post.PostId);

            if (existingPost == null)
            {
                existingBlog.Posts.Add(post);
            }
            else
            {
                context.Entry(existingPost).CurrentValues.SetValues(post);
            }
        }

        foreach (var post in existingBlog.Posts)
        {
            if (!blog.Posts.Any(p => p.PostId == post.PostId))
            {
                context.Remove(post);
            }
        }
    }

    context.SaveChanges();
}

TrackGraphTrackGraph

Wewnętrznie, Dodaj, Dołącz i aktualizacji za pomocą przechodzenie grafu przy podejmowaniu wprowadzone dla każdej jednostki do tego, czy jego powinien być oznaczony jako dodano (Aby wstawić), zmodyfikowany (w celu aktualizacji), Unchanged (NIC), lub usunięte (Aby usunąć).Internally, Add, Attach, and Update use graph-traversal with a determination made for each entity as to whether it should be marked as Added (to insert), Modified (to update), Unchanged (do nothing), or Deleted (to delete). Ten mechanizm jest uwidaczniany za pomocą interfejsu API TrackGraph.This mechanism is exposed via the TrackGraph API. Na przykład załóżmy, że gdy klient wysyła z powrotem wykres jednostek ustawia niektóre flagi dla każdej jednostki wskazujący sposób obsługi.For example, let's assume that when the client sends back a graph of entities it sets some flag on each entity indicating how it should be handled. TrackGraph następnie może służyć do przetwarzania tej flagi:TrackGraph can then be used to process this flag:

public static void SaveAnnotatedGraph(DbContext context, object rootEntity)
{
    context.ChangeTracker.TrackGraph(
        rootEntity,
        n =>
        {
            var entity = (EntityBase)n.Entry.Entity;
            n.Entry.State = entity.IsNew
                ? EntityState.Added
                : entity.IsChanged
                    ? EntityState.Modified
                    : entity.IsDeleted
                        ? EntityState.Deleted
                        : EntityState.Unchanged;
        });

    context.SaveChanges();
}

Flagi są wyświetlane tylko w ramach jednostki dla uproszczenia w przykładzie.The flags are only shown as part of the entity for simplicity of the example. Zazwyczaj flagi powinien być częścią obiekt DTO lub inny stan, zawarty w żądaniu.Typically the flags would be part of a DTO or some other state included in the request.