Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
, DbContext herhangi bir birincil anahtar değerine sahip yalnızca bir varlık örneğini izleyebilir. Bu, aynı anahtar değerine sahip bir varlığın birden çok örneğinin tek bir örneğe çözümlenmesi gerektiği anlamına gelir. Buna "kimlik çözümleme" adı verilir. Kimlik çözümlemesi, Entity Framework Core'un (EF Core) varlıkların ilişkileri veya özellik değerleri hakkında belirsizlik olmadan tutarlı bir graf izlemesini sağlar.
İpucu
Bu belgede varlık durumlarının ve EF Core değişiklik izlemenin temellerinin anlaşıldığı varsayılır. Bu konular hakkında daha fazla bilgi için EF Core'daki Değişiklik İzleme bakın.
İpucu
GitHub’dan örnek kodu indirerek bu belgedeki tüm kodları çalıştırabilir ve hataları ayıklayabilirsiniz.
Giriş
Aşağıdaki kod bir varlık için sorgular ve ardından aynı birincil anahtar değerine sahip farklı bir örnek eklemeyi dener:
using var context = new BlogsContext();
var blogA = await context.Blogs.SingleAsync(e => e.Id == 1);
var blogB = new Blog { Id = 1, Name = ".NET Blog (All new!)" };
try
{
context.Update(blogB); // This will throw
}
catch (Exception e)
{
Console.WriteLine($"{e.GetType().FullName}: {e.Message}");
}
Bu kodun çalıştırılması aşağıdaki özel duruma neden olur:
System.InvalidOperationException: '{Id: 1}' anahtar değerine sahip başka bir örnek zaten izlendiğinden, 'Blog' varlık türünün örneği izlenemiyor. Mevcut varlıkları eklerken, belirli bir anahtar değerine sahip yalnızca bir varlık örneğinin eklendiğinden emin olun.
EF Core için tek bir örnek gerekir çünkü:
- Özellik değerleri birden çok örnek arasında farklı olabilir. Veritabanını güncelleştirirken EF Core'un hangi özellik değerlerinin kullanılacağını bilmesi gerekir.
- Diğer varlıklarla ilişkiler birden çok örnek arasında farklı olabilir. Örneğin, "blogA" "blogB"den farklı bir gönderi koleksiyonuyla ilgili olabilir.
Aşağıdaki durumlarda yukarıdaki özel durumla yaygın olarak karşılaşılır:
- Bir varlığı güncelleştirmeye çalışırken
- Varlıkların seri hale getirilmiş grafiğini izlemeye çalışırken
- Otomatik olarak oluşturulmayan bir anahtar değeri ayarlanamadığında
- Birden çok iş birimi için DbContext örneğini yeniden kullanırken
Bu durumların her biri aşağıdaki bölümlerde açıklanmıştır.
Varlığı güncelleştirme
EF Core'da Değişiklik İzleme ve Varlıkları Açıkça İzleme bölümünde açıklandığı gibi, bir varlığı yeni değerlerle güncelleştirmek için birkaç farklı yaklaşım vardır. Bu yaklaşımlar aşağıda kimlik çözümlemesi bağlamında özetlenmiştir. Dikkat edilmesi gereken önemli bir nokta, yaklaşımların her birinin ya bir sorgu ya da Update veya Attach çağrısı kullanmasıdır, ancak asla her ikisini de kullanmaz.
Arama Güncelleştirmesi
Genellikle güncelleştirilecek varlık, SaveChanges için kullanacağımız DbContext sorgusundan gelmez. Örneğin, bir web uygulamasında post isteğindeki bilgilerden bir varlık örneği oluşturulabilir. Bunu işlemenin en basit yolu DbContext.Update veya DbSet<TEntity>.Update kullanmaktır. Örneğin:
public static async Task UpdateFromHttpPost1(Blog blog)
{
using var context = new BlogsContext();
context.Update(blog);
await context.SaveChangesAsync();
}
Bu durumda:
- Varlığın yalnızca tek bir örneği oluşturulur.
- Varlık örneği, güncelleştirmenin bir parçası olarak veritabanından sorgulanmaz .
- Tüm özellik değerleri, gerçekten değişip değişmediklerine bakılmaksızın veritabanında güncelleştirilir.
- Bir veritabanı gidiş dönüşü gerçekleştirilir.
Sorgu ve ardından değişiklikleri uygulama
Genellikle post isteğindeki veya benzeri bir bilgiden bir varlık oluşturulduğunda hangi özellik değerlerinin gerçekten değiştirildiği bilinmez. Genellikle önceki örnekte yaptığımız gibi veritabanındaki tüm değerleri güncelleştirmek yeterlidir. Ancak, uygulama birçok varlığı işleniyorsa ve yalnızca az sayıda gerçek değişiklik varsa, gönderilen güncelleştirmeleri sınırlamak yararlı olabilir. Bu, veritabanında mevcut olan varlıkları izlemek için bir sorgu yürütülerek ve ardından izlenen bu varlıklara değişiklikler uygulanarak gerçekleştirilebilir. Örneğin:
public static async Task UpdateFromHttpPost2(Blog blog)
{
using var context = new BlogsContext();
var trackedBlog = await context.Blogs.FindAsync(blog.Id);
trackedBlog.Name = blog.Name;
trackedBlog.Summary = blog.Summary;
await context.SaveChangesAsync();
}
Bu durumda:
- Varlığın yalnızca tek bir örneği izlenir; veritabanından
Findsorgusu tarafından döndürülen. -
Update,Attachvb. kullanılmaz. - Veritabanında yalnızca gerçekten değiştirilmiş özellik değerleri güncelleştirilir.
- İki veritabanı gidiş dönüşleri yapılır.
EF Core'un bunun gibi özellik değerlerini aktarmak için bazı yardımcıları vardır. Örneğin, PropertyValues.SetValues verilen nesnedeki tüm değerleri kopyalar ve izlenen nesnede ayarlar:
public static async Task UpdateFromHttpPost3(Blog blog)
{
using var context = new BlogsContext();
var trackedBlog = await context.Blogs.FindAsync(blog.Id);
context.Entry(trackedBlog).CurrentValues.SetValues(blog);
await context.SaveChangesAsync();
}
SetValues varlık türünün özellikleriyle eşleşen özellik adlarına sahip veri aktarım nesneleri (DTO' lar) dahil olmak üzere çeşitli nesne türlerini kabul eder. Örneğin:
public static async Task UpdateFromHttpPost4(BlogDto dto)
{
using var context = new BlogsContext();
var trackedBlog = await context.Blogs.FindAsync(dto.Id);
context.Entry(trackedBlog).CurrentValues.SetValues(dto);
await context.SaveChangesAsync();
}
Veya özellik değerleri için ad/değer girdileri içeren bir sözlük:
public static async Task UpdateFromHttpPost5(Dictionary<string, object> propertyValues)
{
using var context = new BlogsContext();
var trackedBlog = await context.Blogs.FindAsync(propertyValues["Id"]);
context.Entry(trackedBlog).CurrentValues.SetValues(propertyValues);
await context.SaveChangesAsync();
}
Bunun gibi özellik değerleriyle çalışmak hakkında daha fazla bilgi için bkz İzlenen varlıklara erişme.
Özgün değerleri kullanma
Şimdiye kadar her yaklaşım güncelleştirmeyi yapmadan önce bir sorgu yürütmüştür veya değiştirilip değiştirilmediğinden bağımsız olarak tüm özellik değerlerini güncelleştirmiştir. Yalnızca güncelleştirmenin bir parçası olarak sorgulanmadan değiştirilen değerleri güncelleştirmek için hangi özellik değerlerinin değiştirildiği hakkında belirli bilgiler gerekir. Bu bilgileri edinmenin yaygın yollarından biri, HTTP Gönderisindeki veya benzeri geçerli ve özgün değerleri geri göndermektir. Örneğin:
public static async Task UpdateFromHttpPost6(Blog blog, Dictionary<string, object> originalValues)
{
using var context = new BlogsContext();
context.Attach(blog);
context.Entry(blog).OriginalValues.SetValues(originalValues);
await context.SaveChangesAsync();
}
Bu kodda, değiştirilen değerlere sahip varlık ilk olarak eklenir. Bu, EF Core'un durumundaki Unchanged varlığı izlemesine neden olur; başka bir ifadeyle, değiştirilmiş olarak işaretlenen özellik değerleri yoktur. Özgün değerlerin sözlüğü daha sonra bu izlenen varlığa uygulanır. Bu, farklı geçerli ve özgün değerlerle değiştirilmiş özellikler olarak işaretlenir. Aynı geçerli ve özgün değerlere sahip özellikler değiştirilmiş olarak işaretlenmez.
Bu durumda:
- Ekle işlevi kullanılarak varlığın yalnızca tek bir nesnesi izlenir.
- Varlık örneği, güncelleştirmenin bir parçası olarak veritabanından sorgulanmaz .
- Özgün değerlerin uygulanması, veritabanında yalnızca gerçekten değiştirilmiş özellik değerlerinin güncelleştirilmesini sağlar.
- Bir veritabanı gidiş dönüşü gerçekleştirilir.
Önceki bölümdeki örneklerde olduğu gibi, özgün değerlerin sözlük olarak geçirilmesi gerekmez; bir varlık örneği veya DTO da çalışır.
İpucu
Bu yaklaşım cazip özelliklere sahip olsa da, varlığın özgün değerlerinin web istemcisine ve web istemcisinden gönderilmesini gerektirir. Bu ekstra karmaşıklığın avantajlara değip değmediğini dikkatlice düşünün; birçok uygulama için daha basit yaklaşımlardan biri daha pragmatiktir.
Seri hale getirilmiş grafik ekleme
EF Core, Yabancı Anahtarları ve Gezintileri Değiştirme bölümünde açıklandığı gibi, yabancı anahtarlar ve gezinti özellikleri aracılığıyla bağlanan varlıkların grafikleriyle çalışır. Bu grafikler, örneğin bir JSON dosyasından kullanılarak EF Core dışında oluşturulursa, aynı varlığın birden çok örneğine sahip olabilirler. Grafın izlenebilmesi için bu yinelenenlerin tek örnekler halinde çözümlenmesi gerekir.
Yinelenenleri olmayan grafikler
Daha ileri gitmeden önce, şu hususların farkına varmak önemlidir:
- Seri hale getiriciler genellikle grafikteki döngüleri ve yinelenen örnekleri işleme seçeneklerine sahiptir.
- Graf kökü olarak kullanılan nesne seçimi genellikle yinelenenleri azaltmaya veya kaldırmaya yardımcı olabilir.
Mümkünse serileştirme seçeneklerini kullanın ve yinelenenlere neden olmayan kökler seçin. Örneğin, aşağıdaki kod her biri ilişkili gönderileriyle birlikte bir blog listesini seri hale getirmek için Json.NET kullanır:
using var context = new BlogsContext();
var blogs = await context.Blogs.Include(e => e.Posts).ToListAsync();
var serialized = JsonConvert.SerializeObject(
blogs,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, Formatting = Formatting.Indented });
Console.WriteLine(serialized);
Bu koddan oluşturulan JSON şöyledir:
[
{
"Id": 1,
"Name": ".NET Blog",
"Summary": "Posts about .NET",
"Posts": [
{
"Id": 1,
"Title": "Announcing the Release of EF Core 5.0",
"Content": "Announcing the release of EF Core 5.0, a full featured cross-platform...",
"BlogId": 1
},
{
"Id": 2,
"Title": "Announcing F# 5",
"Content": "F# 5 is the latest version of F#, the functional programming language...",
"BlogId": 1
}
]
},
{
"Id": 2,
"Name": "Visual Studio Blog",
"Summary": "Posts about Visual Studio",
"Posts": [
{
"Id": 3,
"Title": "Disassembly improvements for optimized managed debugging",
"Content": "If you are focused on squeezing out the last bits of performance for your .NET service or...",
"BlogId": 2
},
{
"Id": 4,
"Title": "Database Profiling with Visual Studio",
"Content": "Examine when database queries were executed and measure how long the take using...",
"BlogId": 2
}
]
}
]
JSON'da yinelenen blog veya gönderi olmadığına dikkat edin. Bu, basit çağrıların Update veritabanındaki bu varlıkları güncelleştirmek için çalışacağı anlamına gelir:
public static async Task UpdateBlogsFromJson(string json)
{
using var context = new BlogsContext();
var blogs = JsonConvert.DeserializeObject<List<Blog>>(json);
foreach (var blog in blogs)
{
context.Update(blog);
}
await context.SaveChangesAsync();
}
Yinelenenleri işleme
Önceki örnekteki kod, her blogu ilişkili gönderileriyle seri hale getirmiştir. Bu, her gönderiyi ilişkili bloguyla seri hale getirmek üzere değiştirilirse, serileştirilmiş JSON'a çift kayıtlar eklenmiş olur. Örneğin:
using var context = new BlogsContext();
var posts = await context.Posts.Include(e => e.Blog).ToListAsync();
var serialized = JsonConvert.SerializeObject(
posts,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, Formatting = Formatting.Indented });
Console.WriteLine(serialized);
Serileştirilmiş JSON şimdi şöyle görünür:
[
{
"Id": 1,
"Title": "Announcing the Release of EF Core 5.0",
"Content": "Announcing the release of EF Core 5.0, a full featured cross-platform...",
"BlogId": 1,
"Blog": {
"Id": 1,
"Name": ".NET Blog",
"Summary": "Posts about .NET",
"Posts": [
{
"Id": 2,
"Title": "Announcing F# 5",
"Content": "F# 5 is the latest version of F#, the functional programming language...",
"BlogId": 1
}
]
}
},
{
"Id": 2,
"Title": "Announcing F# 5",
"Content": "F# 5 is the latest version of F#, the functional programming language...",
"BlogId": 1,
"Blog": {
"Id": 1,
"Name": ".NET Blog",
"Summary": "Posts about .NET",
"Posts": [
{
"Id": 1,
"Title": "Announcing the Release of EF Core 5.0",
"Content": "Announcing the release of EF Core 5.0, a full featured cross-platform...",
"BlogId": 1
}
]
}
},
{
"Id": 3,
"Title": "Disassembly improvements for optimized managed debugging",
"Content": "If you are focused on squeezing out the last bits of performance for your .NET service or...",
"BlogId": 2,
"Blog": {
"Id": 2,
"Name": "Visual Studio Blog",
"Summary": "Posts about Visual Studio",
"Posts": [
{
"Id": 4,
"Title": "Database Profiling with Visual Studio",
"Content": "Examine when database queries were executed and measure how long the take using...",
"BlogId": 2
}
]
}
},
{
"Id": 4,
"Title": "Database Profiling with Visual Studio",
"Content": "Examine when database queries were executed and measure how long the take using...",
"BlogId": 2,
"Blog": {
"Id": 2,
"Name": "Visual Studio Blog",
"Summary": "Posts about Visual Studio",
"Posts": [
{
"Id": 3,
"Title": "Disassembly improvements for optimized managed debugging",
"Content": "If you are focused on squeezing out the last bits of performance for your .NET service or...",
"BlogId": 2
}
]
}
}
]
Grafın artık aynı anahtar değerine sahip birden çok Blog örneğini ve aynı anahtar değerine sahip birden çok Post örneğini içerdiğine dikkat edin. Bu grafiği önceki örnekte yaptığımız gibi izlemeye çalışmak şu şekilde olacaktır:
System.InvalidOperationException: '{Id: 2}' anahtar değerine sahip başka bir örnek zaten izlendiğinden, 'Post' varlık türünün örneği izlenemiyor. Mevcut varlıkları eklerken, belirli bir anahtar değerine sahip yalnızca bir varlık örneğinin eklendiğinden emin olun.
Bunu iki yolla düzeltebiliriz:
- Referansları koruyan JSON serileştirme seçeneklerini kullanın.
- Grafik izlenmekteyken kimlik çözümlemesi gerçekleştirme
Referansları koruma
Json.NET bunu işleme seçeneği sağlar PreserveReferencesHandling . Örneğin:
var serialized = JsonConvert.SerializeObject(
posts,
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All, Formatting = Formatting.Indented
});
Sonuçta elde edilen JSON şimdi şöyle görünür:
{
"$id": "1",
"$values": [
{
"$id": "2",
"Id": 1,
"Title": "Announcing the Release of EF Core 5.0",
"Content": "Announcing the release of EF Core 5.0, a full featured cross-platform...",
"BlogId": 1,
"Blog": {
"$id": "3",
"Id": 1,
"Name": ".NET Blog",
"Summary": "Posts about .NET",
"Posts": [
{
"$ref": "2"
},
{
"$id": "4",
"Id": 2,
"Title": "Announcing F# 5",
"Content": "F# 5 is the latest version of F#, the functional programming language...",
"BlogId": 1,
"Blog": {
"$ref": "3"
}
}
]
}
},
{
"$ref": "4"
},
{
"$id": "5",
"Id": 3,
"Title": "Disassembly improvements for optimized managed debugging",
"Content": "If you are focused on squeezing out the last bits of performance for your .NET service or...",
"BlogId": 2,
"Blog": {
"$id": "6",
"Id": 2,
"Name": "Visual Studio Blog",
"Summary": "Posts about Visual Studio",
"Posts": [
{
"$ref": "5"
},
{
"$id": "7",
"Id": 4,
"Title": "Database Profiling with Visual Studio",
"Content": "Examine when database queries were executed and measure how long the take using...",
"BlogId": 2,
"Blog": {
"$ref": "6"
}
}
]
}
},
{
"$ref": "7"
}
]
}
Halihazırda grafikte var olan örneklere atıfta bulunan "$ref": "5" gibi referanslarla bu JSON'un yinelenenleri değiştirdiğine dikkat edin. Bu grafik, yukarıda gösterildiği gibi Update kullanılarak yapılan basit çağrılar ile yeniden izlenebilir.
System.Text.Json.NET temel sınıf kitaplıklarındaki (BCL) destek, aynı sonucu veren benzer bir seçeneğe sahiptir. Örneğin:
var serialized = JsonSerializer.Serialize(
posts, new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve, WriteIndented = true });
Yinelenenleri kaldır
Serileştirme işleminde yinelenenleri ortadan kaldırmak mümkün değilse, ChangeTracker.TrackGraph bunu işlemek için bir yol sağlar. TrackGraph, Add, Attach ve Update gibi çalışır ancak izlemeden önce her varlık örneği için bir geri çağırma oluşturur. Bu geri çağırma, varlığı izlemek veya yoksaymak için kullanılabilir. Örneğin:
public static async Task UpdatePostsFromJsonWithIdentityResolution(string json)
{
using var context = new BlogsContext();
var posts = JsonConvert.DeserializeObject<List<Post>>(json);
foreach (var post in posts)
{
context.ChangeTracker.TrackGraph(
post, node =>
{
var keyValue = node.Entry.Property("Id").CurrentValue;
var entityType = node.Entry.Metadata;
var existingEntity = node.Entry.Context.ChangeTracker.Entries()
.FirstOrDefault(
e => Equals(e.Metadata, entityType)
&& Equals(e.Property("Id").CurrentValue, keyValue));
if (existingEntity == null)
{
Console.WriteLine($"Tracking {entityType.DisplayName()} entity with key value {keyValue}");
node.Entry.State = EntityState.Modified;
}
else
{
Console.WriteLine($"Discarding duplicate {entityType.DisplayName()} entity with key value {keyValue}");
}
});
}
await context.SaveChangesAsync();
}
Grafikteki her varlık için bu kod şunları yapacaktır:
- Varlığın varlık türünü ve anahtar değerini bulma
- Değişiklik izleyicisinde bu anahtarla varlığı ara
- Varlık bulunursa, varlık tekrarlanan bir varlık olduğundan başka bir işlem yapılmaz.
- Varlık bulunamazsa, durum
Modifiedolarak ayarlanarak izlenir.
Bu kodu çalıştırmanın çıkışı şu şekildedir:
Tracking EntityType: Post entity with key value 1
Tracking EntityType: Blog entity with key value 1
Tracking EntityType: Post entity with key value 2
Discarding duplicate EntityType: Post entity with key value 2
Tracking EntityType: Post entity with key value 3
Tracking EntityType: Blog entity with key value 2
Tracking EntityType: Post entity with key value 4
Discarding duplicate EntityType: Post entity with key value 4
Önemli
Bu kod , tüm yinelemelerin aynı olduğunu varsayar. Diğerlerini elerken, yinelemelerden birini gelişigüzel seçmeyi güvenli hale getirir. Yinelemeler farklı olabilirse, kodun hangisinin kullanılacağını ve özellik ile gezinti değerlerinin birlikte nasıl birleştirileceğini belirlemesi gerekir.
Not
Kolaylık olması için, bu kod her varlığın adlı Idbir birincil anahtar özelliği olduğunu varsayar. Bu, soyut bir temel sınıf veya arabirime kodlanabilir. Alternatif olarak, bu kodun herhangi bir varlık türüyle çalışması için birincil anahtar özelliği veya özellikleri meta verilerden IEntityType alınabilir.
Anahtar değerlerin ayarlanamaması
Varlık türleri genellikle otomatik olarak oluşturulan anahtar değerlerini kullanacak şekilde yapılandırılır. Bu, bileşik olmayan anahtarların tamsayı ve GUID özellikleri için varsayılan değerdir. Ancak, varlık türü otomatik olarak oluşturulan anahtar değerlerini kullanacak şekilde yapılandırılmamışsa, varlığı izlemeden önce açık bir anahtar değeri ayarlanmalıdır. Örneğin, aşağıdaki varlık türünü kullanarak:
public class Pet
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Name { get; set; }
}
Anahtar değerleri ayarlamadan iki yeni varlık örneğini izlemeye çalışan kodu göz önünde bulundurun:
using var context = new BlogsContext();
context.Add(new Pet { Name = "Smokey" });
try
{
context.Add(new Pet { Name = "Clippy" }); // This will throw
}
catch (Exception e)
{
Console.WriteLine($"{e.GetType().FullName}: {e.Message}");
}
Bu kod şu şekilde olacaktır:
System.InvalidOperationException: '{Id: 0}' anahtar değerine sahip başka bir örnek zaten izlendiğinden, 'Pet' varlık türünün örneği izlenemiyor. Mevcut varlıkları eklerken, belirli bir anahtar değerine sahip yalnızca bir varlık örneğinin eklendiğinden emin olun.
Bunun düzeltmesi, anahtar değerlerini açıkça ayarlamak veya anahtar özelliğini oluşturulan anahtar değerlerini kullanacak şekilde yapılandırmaktır. Daha fazla bilgi için bkz . Oluşturulan Değerler .
Tek bir DbContext örneğini aşırı kullanma
DbContext, DbContext Başlatma ve Yapılandırma bölümünde açıklandığı gibi kısa süreli bir çalışma birimini temsil etmek için tasarlanmıştır ve EF Core'da Değişiklik İzleme üzerinde ayrıntılı olarak açıklanmıştır. Bu kılavuzun izlenmemesi, aynı varlığın birden çok örneğini takip etmeye çalışırken karşılaşılması kolay durumlara neden olur. Sık karşılaşılan örnekler:
- Hem test durumunu ayarlamak hem de testi yürütmek için aynı DbContext örneğini kullanma. Bu durum genellikle DbContext'in test kurulumundan bir varlık örneğini izlemeye devam ederken teste uygun şekilde yeni bir örnek eklemeyi denemesine neden olur. Bunun yerine, test durumunu ve test kodunu düzgün ayarlamak için farklı bir DbContext örneği kullanın.
- Depoda veya benzer bir kodda paylaşılan bir DbContext örneği kullanma. Bunun yerine, deponuzun her çalışma birimi için tek bir DbContext örneği kullandığından emin olun.
Kimlik çözümleme ve sorgular
Varlıklar bir sorgudan izlendiğinde kimlik çözümlemesi otomatik olarak gerçekleşir. Başka bir deyişle, belirli bir anahtar değerine sahip bir varlık örneği zaten izleniyorsa, yeni bir örnek oluşturmak yerine bu mevcut izlenen örnek kullanılır. Bunun önemli bir sonucu vardır: Veritabanında veriler değiştiyse, bu sorgu sonuçlarına yansıtılmaz. Bu, DbContext Başlatma ve Yapılandırma bölümünde açıklandığı gibi ve EF Core'daki Değişiklik İzleme'de açıklandığı gibi her çalışma birimi için yeni bir DbContext örneği kullanmak için iyi bir nedendir.
Önemli
EF Core'un veritabanına karşı her zaman bir DbSet üzerinde LINQ sorgusu yürüttüğü ve yalnızca veritabanındakilere göre sonuçları döndürdüğünü anlamak önemlidir. Ancak, bir izleme sorgusu için, döndürülen varlıklar zaten izleniyorsa, veritabanındaki verilerden örnekler oluşturmak yerine izlenen örnekler kullanılır.
Reload() veya GetDatabaseValues() izlenen varlıkların veritabanındaki en son verilerle yenilenmesi gerektiğinde kullanılabilir. Daha fazla bilgi için bkz . İzlenen Varlıklara Erişme.
İzleme sorgularının aksine, izlemesiz sorgular kimlik çözümlemesi gerçekleştirmez. Bu, izlemesiz sorguların daha önce açıklanan JSON serileştirme örneğinde olduğu gibi yinelenenleri döndürebileceği anlamına gelir. Sorgu sonuçları seri hale getirilecek ve istemciye gönderilecekse bu genellikle bir sorun değildir.
İpucu
Düzenli olarak izleme olmadan bir sorgu gerçekleştirip döndürülen varlıkları aynı bağlamda eklemeyin. Bunu yapmak, bir izleme sorgusu kullanmaktan daha yavaş ve daha zor olacaktır.
İzleme yapılmayan sorgular kimlik çözümlemesi gerçekleştirmez, çünkü bunu yapmak sorgudan çok sayıda varlığın aktarım performansını etkiler. Bunun nedeni, kimlik çözümlemesinin daha sonra yineleme oluşturmak yerine kullanılabilmesi için döndürülen her örneğin izlenmesini gerektirmesidir.
İzlemesiz sorgular, kimlik çözümlemesi yapmaya AsNoTrackingWithIdentityResolution<TEntity>(IQueryable<TEntity>) kullanılarak zorlanabilir. Sorgu daha sonra döndürülen örnekleri (normal şekilde izlemeden) izler ve sorgu sonuçlarında yineleme oluşturulmadığından emin olur.
Nesne eşitliğini geçersiz kılma
EF Core, varlık örneklerini karşılaştırırken başvuru eşitliğini kullanır. Varlık türleri nesne eşitliğini geçersiz kılsa Object.Equals(Object) veya başka bir şekilde değiştirse bile bu durum geçerlidir. Ancak, eşitliğin geçersiz kılınmasının EF Core davranışını etkileyebileceği bir yer vardır: koleksiyon gezinimleri, başvuru eşitliği yerine geçersiz kılınmış eşitliği kullandığında ve bu nedenle birden fazla örneği aynı şekilde raporladığında.
Bu nedenle, varlık eşitliğinin geçersiz kılınmasından kaçınılması önerilir. Kullanılıyorsa, başvuru eşitliğini zorlayan koleksiyon gezintileri oluşturduğunuzdan emin olun. Örneğin, başvuru eşitliği kullanan bir eşitlik karşılaştırıcısı oluşturun:
public sealed class ReferenceEqualityComparer : IEqualityComparer<object>
{
private ReferenceEqualityComparer()
{
}
public static ReferenceEqualityComparer Instance { get; } = new ReferenceEqualityComparer();
bool IEqualityComparer<object>.Equals(object x, object y) => x == y;
int IEqualityComparer<object>.GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj);
}
(.NET 5'den başlayarak, bu BCL'ye ReferenceEqualityComparerolarak eklenir.)
Bu karşılaştırıcı daha sonra koleksiyon gezintileri oluştururken kullanılabilir. Örneğin:
public ICollection<Order> Orders { get; set; }
= new HashSet<Order>(ReferenceEqualityComparer.Instance);
Anahtar özellikleri karşılaştırma
Eşitlik karşılaştırmalarına ek olarak anahtar değerlerin de sıralanması gerekir. Bu, Tek bir SaveChanges çağrısında birden çok varlığı güncelleştirirken kilitlenmeleri önlemek için önemlidir. Birincil, alternatif veya yabancı anahtar özellikleri için kullanılan tüm türlerin yanı sıra benzersiz dizinler için kullanılanların IComparable<T> ve IEquatable<T> uygulamaları gerekir. Normalde anahtar olarak kullanılan türler (int, Guid, dize vb.) zaten bu arabirimleri destekler. Özel anahtar türleri bu arabirimleri ekleyebilir.