Bağlantısı kesilen varlıklarDisconnected entities

DbContext örneği, veritabanından döndürülen varlıkları otomatik olarak izler.A DbContext instance will automatically track entities returned from the database. SaveChanges çağrıldığında bu varlıklarda yapılan değişiklikler algılanır ve veritabanı gerektiği gibi güncelleştirilir.Changes made to these entities will then be detected when SaveChanges is called and the database will be updated as needed. Ayrıntılar için Temel Kaydet ve İlgili Verilere bakın.See Basic Save and Related Data for details.

Ancak, bazen varlıklar tek bir bağlam örneği kullanılarak sorgulanır ve sonra farklı bir örnek kullanılarak kaydedilir.However, sometimes entities are queried using one context instance and then saved using a different instance. Bu genellikle varlıkların sorgulandığı, istemciye gönderildiği, değiştirildiği, istekte sunucuya geri gönderildiği ve sonra kaydedildiği bir web uygulaması gibi "bağlantısı kesilmiş" senaryolarda gerçekleşir.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. Bu durumda, ikinci bağlam örneğinin varlıkların yeni mi yoksa varolan mı (güncelleştirilmelidir) olup olmadığını bilmesi gerekir.In this case, the second context instance needs to know whether the entities are new (should be inserted) or existing (should be updated).

İpucu

Bu makalenin örneğini GitHub'da görüntüleyebilirsiniz.You can view this article's sample on GitHub.

İpucu

EF Core, belirli bir birincil anahtar değeri olan herhangi bir varlığın yalnızca bir örneğini izleyebilir.EF Core can only track one instance of any entity with a given primary key value. Bu bir sorun olmasını önlemenin en iyi yolu, her bir çalışma birimi için bağlamın boş başlaması, ona bağlı varlıkların olması, bu varlıkların kaydedilmesi ve bağlamın bertaraf edilip atılması gibi kısa ömürlü bir bağlam kullanmaktır.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.

Yeni varlıkların tanımlanmasıIdentifying new entities

İstemci yeni varlıkları tanımlarClient identifies new entities

Ele almak için en basit durumda istemci varlığı yeni veya varolan olup olmadığını sunucuya bildirir.The simplest case to deal with is when the client informs the server whether the entity is new or existing. Örneğin, genellikle yeni bir varlık ekleme isteği varolan bir varlığı güncelleştirme isteğifarklıdır.For example, often the request to insert a new entity is different from the request to update an existing entity.

Bu bölümün geri kalanı, eklemek veya güncelleştirmek için başka bir şekilde belirlemek için gerekli durumlarda kapsar.The remainder of this section covers the cases where it necessary to determine in some other way whether to insert or update.

Otomatik oluşturulan anahtarlarlaWith auto-generated keys

Otomatik olarak oluşturulan anahtarın değeri genellikle bir varlığın eklenmesi veya güncelleştirilmesi gerekip gerekmediğini belirlemek için kullanılabilir.The value of an automatically generated key can often be used to determine whether an entity needs to be inserted or updated. Anahtar ayarlanmadıysa (diğer bir deyişle, hala null, sıfır, vb CLR varsayılan değerine sahip), o zaman varlık yeni olmalı ve ekleme ihtiyacı vardır.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. Diğer taraftan, anahtar değeri ayarlanmışsa, daha önce kaydedilmiş olması gerekir ve şimdi güncelleştirilmesi gerekir.On the other hand, if the key value has been set, then it must have already been previously saved and now needs updating. Başka bir deyişle, anahtarın bir değeri varsa, varlık sorgulandı, istemciye gönderildi ve şimdi güncellenmek üzere geri geldi.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.

Varlık türü bilindiğinde ayarlanmamış anahtarı denetlemek kolaydır:It is easy to check for an unset key when the entity type is known:

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

Ancak, EF de herhangi bir varlık türü ve anahtar türü için bunu yapmak için yerleşik bir şekilde vardır: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;

İpucu

Varlıklar bağlam tarafından izlenir izlenmez, varlık Eklenen durumda olsa bile anahtarlar ayarlanır.Keys are set as soon as entities are tracked by the context, even if the entity is in the Added state. Bu, varlıkların bir grafiğini dolaşırken ve TrackGraph API'sını kullanırken olduğu gibi her biriyle ne yapacağınız konusunda karar verirken yardımcı olur.This helps when traversing a graph of entities and deciding what to do with each, such as when using the TrackGraph API. Anahtar değeri, varlığı izlemek için herhangi bir arama yapılmadan önce yalnızca burada gösterilen şekilde kullanılmalıdır.The key value should only be used in the way shown here before any call is made to track the entity.

Diğer tuşlarlaWith other keys

Anahtar değerler otomatik olarak oluşturulmadığında yeni varlıkları tanımlamak için başka bir mekanizma gerekir.Some other mechanism is needed to identify new entities when key values are not generated automatically. Bunun iki genel yaklaşımı vardır:There are two general approaches to this:

  • Varlık için sorguQuery for the entity
  • İstemciden bayrak geçirPass a flag from the client

Varlığı sorgulamak için Bul yöntemini kullanman:To query for the entity, just use the Find method:

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

Bir istemciden bayrak geçirmek için tam kodu göstermek için bu belgenin kapsamı dışındadır.It is beyond the scope of this document to show the full code for passing a flag from a client. Bir web uygulamasında, genellikle farklı eylemler için farklı isteklerde bulunmak veya istekteki bazı durumları geçmek ve denetleyicide ayıklamak anlamına gelir.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.

Tek varlıkları kaydetmeSaving single entities

Bir ekleme veya güncelleştirme gerekip gerekmediği biliniyorsa, Ekle veya Güncelleştir uygun şekilde kullanılabilir: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();
}

Ancak, varlık otomatik olarak oluşturulan anahtar değerlerini kullanıyorsa, güncelleştirme yöntemi her iki durum için de kullanılabilir: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();
}

Güncelleştirme yöntemi normalde ekleme değil, güncelleştirme için varlık işaretler.The Update method normally marks the entity for update, not insert. Ancak, varlığın otomatik olarak oluşturulan bir anahtarı varsa ve anahtar değeri ayarlanmadıysa, varlık eklemek için otomatik olarak işaretlenir.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.

İpucu

Bu davranış EF Core 2.0'da sunulmuştur.This behavior was introduced in EF Core 2.0. Önceki sürümler için her zaman açıkça Ekle veya Güncelleştir'i seçmek gerekir.For earlier releases it is always necessary to explicitly choose either Add or Update.

Varlık otomatik olarak oluşturulan anahtarları kullanmıyorsa, uygulama varlığın eklenmesi mi yoksa güncelleştirilmesi mi gerektiğine karar vermelidir: Örneğin: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();
}

Burada adımlar şunlardır:The steps here are:

  • Bul döndürür null dönerse, veritabanı zaten bu kimliği içeren blog içermez, bu yüzden ekleme için işaretle diyoruz.If Find returns null, then the database doesn't already contain the blog with this ID, so we call Add mark it for insertion.
  • Find bir varlığı döndürürse, veritabanında var olur ve bağlam şimdi varolan varlığı takip ediyorIf Find returns an entity, then it exists in the database and the context is now tracking the existing entity
    • Daha sonra, bu varlıktaki tüm özelliklerin değerlerini istemciden gelenlere ayarlamak için SetValues'i kullanırız.We then use SetValues to set the values for all properties on this entity to those that came from the client.
    • SetValues çağrısı, gerektiğinde güncelleştirilecek varlığı işaretler.The SetValues call will mark the entity to be updated as needed.

İpucu

SetDeğerleri yalnızca izlenen varlıktakilerle farklı değerlere sahip özellikleri değiştirilmiş olarak işaretler.SetValues will only mark as modified the properties that have different values to those in the tracked entity. Bu, güncelleştirme gönderildiğinde yalnızca gerçekten değiştirilen sütunların güncelleştirileceği anlamına gelir.This means that when the update is sent, only those columns that have actually changed will be updated. (Ve hiçbir şey değişmediyse, o zaman hiçbir güncelleştirme gönderilmez.)(And if nothing has changed, then no update will be sent at all.)

Grafiklerle çalışmaWorking with graphs

Kimlik çözünürlüğüIdentity resolution

Yukarıda belirtildiği gibi, EF Core yalnızca belirli bir birincil anahtar değeri olan herhangi bir varlığın bir örneğini izleyebilir.As noted above, EF Core can only track one instance of any entity with a given primary key value. Grafiklerle çalışırken grafik ideal olarak bu değişmezin korunması ve bağlamın yalnızca bir çalışma birimi için kullanılması gibi oluşturulmalıdır.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. Grafik yinelemeler içeriyorsa, birden çok örneği tek bir örnekte birleştirmek için grafiği EF'ye göndermeden önce işlemek gerekir.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. Örneklerin çakışan değerler eve sahip olduğu bu önemsiz olmayabilir, bu nedenle çakışma çözümünü önlemek için uygulama ardışık bilgisayarınızda yinelenenleri en kısa sürede birleştirme yapılmalıdır.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.

Tüm yeni/tüm mevcut varlıklarAll new/all existing entities

Grafiklerle çalışmanın bir örneği, bir blogu ilişkili gönderikoleksiyonuyla birlikte eklemek veya güncelleştirmektir.An example of working with graphs is inserting or updating a blog together with its collection of associated posts. Grafikteki tüm varlıklar eklenmelidir veya tümü güncelleştirilmelidir, işlem tek varlıklar için yukarıda açıklandığı gibi aynıdır.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. Örneğin, aşağıdaki gibi oluşturulan blogların ve gönderilerin grafiği: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"},
    }
};

şu şekilde eklenebilir:can be inserted like this:

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

Ekle'ye çağrı, blogu ve eklenecek tüm gönderileri işaretler.The call to Add will mark the blog and all the posts to be inserted.

Aynı şekilde, grafikteki tüm varlıkların güncellenmesi gerekiyorsa, Güncelleştirme kullanılabilir: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 ve tüm gönderileri güncellenmek üzere işaretlenecektir.The blog and all its posts will be marked to be updated.

Yeni ve mevcut varlıkların karışımıMix of new and existing entities

Otomatik olarak oluşturulan anahtarlarla, grafik ekleme ve güncelleştirme gerektiren varlıkların bir karışımını içerse bile, Güncelleştirme hem ekler hem de güncelleştirmeler için yeniden kullanılabilir: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();
}

Güncelleştirme, önemli bir değer kümesi yoksa, diğer tüm varlıklar güncelleştirme için işaretlenmiş ise ekleme için grafik, blog veya gönderideki herhangi bir varlığı işaretler.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.

Daha önce olduğu gibi, otomatik olarak oluşturulan anahtarları kullanmadığınızda, bir sorgu ve bazı işleme kullanılabilir: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();
}

İşleme silerHandling deletes

Silme, genellikle bir varlığın yokluğu silinmesi gerektiği anlamına geldiğinden, işlemek zor olabilir.Delete can be tricky to handle since often the absence of an entity means that it should be deleted. Bununla başa çıkmanın bir yolu, varlığın gerçekten silinmek yerine silinmiş olarak işaretlendiğini "yumuşak silmeler" kullanmaktır.One way to deal with this is to use "soft deletes" such that the entity is marked as deleted rather than actually being deleted. Siler sonra güncelleştirmeleri aynı olur.Deletes then becomes the same as updates. Yumuşak silmesorgu filtrelerikullanılarak uygulanabilir.Soft deletes can be implemented in using query filters.

Gerçek siler için, ortak bir desen aslında bir grafik diff ne gerçekleştirmek için sorgu deseni bir uzantısı kullanmaktır.For true deletes, a common pattern is to use an extension of the query pattern to perform what is essentially a graph diff. Örneğin: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

Dahili olarak, Ekle, Ekle ve Güncelleştir, her varlık için eklenen (eklemek için), Değiştirilen (güncelleştirmek için), Değiştirilmeden (hiçbir şey yapmamak) veya Silinmiş (silinecek) olarak işaretlenip işaretlenmemesi gerektiği konusunda yapılan bir kararlılıkla grafik-traversal kullanın.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). Bu mekanizma TrackGraph API ile ortaya çıkarır.This mechanism is exposed via the TrackGraph API. Örneğin, istemci varlıkların bir grafik geri gönderdiğinde, nasıl işlenmesi gerektiğini belirten her varlık üzerinde bazı bayrak ayarlar varsayalım.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 daha sonra bu bayrağı işlemek için kullanılabilir: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();
}

Bayraklar yalnızca örneğin basitliği için varlığın bir parçası olarak gösterilir.The flags are only shown as part of the entity for simplicity of the example. Genellikle bayraklar, isteğe dahil edilmiş bir DTO'nun veya başka bir durum durumunun bir parçası olur.Typically the flags would be part of a DTO or some other state included in the request.