EF Core'da Kimlik Çözümleme
, 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 noktalardan biri, yaklaşımların her birinin ya bir sorgu ya da ya da çağrısı Update
Attach
kullanmasıdır, ancak 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 veya DbSet<TEntity>.UpdatekullanmaktırDbContext.Update. Ö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üş yapılır.
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; sorgu tarafından
Find
veritabanından döndürülen. Update
,Attach
vb. 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ışma 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 kullanılarak varlığın yalnızca tek bir örneği 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üş yapılır.
Ö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 için değiştirilirse, serileştirilmiş JSON'a yinelenenler eklenir. Ö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:
- Başvuruları koruyan JSON serileştirme seçeneklerini kullanma
- Grafik izlenirken kimlik çözümlemesi gerçekleştirme
Başvuruları 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"
}
]
}
Bu JSON'un yinelenenleri grafikte zaten var olan örneğe başvuran başvurularla "$ref": "5"
değiştirdiğini fark edin. Bu grafik, yukarıda gösterildiği gibi öğesine yapılan basit çağrılar Update
kullanılarak 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 çözme
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 gibi Add
Attach
çalışır ve Update
izlemeden önce her varlık örneği için bir geri çağırma oluşturması dışında. 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ığı arama
- Varlık bulunursa, varlık yinelenen olduğundan başka bir işlem yapılmaz
- Varlık bulunamazsa, durum ayarlanarak izlenir
Modified
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. Bu, diğerlerini atarken izlemek üzere yinelenenlerden birini rastgele 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ı Id
bir birincil anahtar özelliği olduğunu varsayar. Bu, soyut bir temel sınıf veya arabirimde codified olabilir. 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ğerleri 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 izleme girişiminde bulunulduğu durumlarda çalıştırmayı kolaylaştırır. 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 bir izleme yok sorgusu gerçekleştirip döndürülen varlıkları aynı bağlama eklemeyin. Bunu yapmak, bir izleme sorgusu kullanmaktan daha yavaş ve daha zor olacaktır.
İzlemesiz sorgular kimlik çözümlemesi gerçekleştirmez, çünkü bunu yapmak sorgudan çok sayıda varlığın akışının 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 kullanılarak AsNoTrackingWithIdentityResolution<TEntity>(IQueryable<TEntity>)kimlik çözümlemesi yapmaya 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ı etkilediği bir yer vardır: koleksiyon gezintileri başvuru eşitliği yerine geçersiz kılınan eşitliği kullandığında ve bu nedenle birden çok ö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 ve IEquatable<T>uygulaması IComparable<T> gerekir. Normalde anahtar olarak kullanılan türler (int, Guid, dize vb.) zaten bu arabirimleri destekler. Özel anahtar türleri bu arabirimleri ekleyebilir.