-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lookup tracked entities by primary key, alternate key, or foreign key #29685
Labels
area-change-tracking
area-dbcontext
closed-fixed
The issue has been fixed and is/will be included in the release indicated by the issue milestone.
type-enhancement
Milestone
Comments
Benchmarks after implementation in #29686:
using System.ComponentModel.DataAnnotations.Schema;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;
BenchmarkRunner.Run<Benchmarks>();
public class Benchmarks
{
private static readonly TestContext Context;
private static readonly IProperty AlternateKeyProperty;
private static readonly IProperty ForeignKeyProperty;
private static readonly IProperty NonKeyProperty;
static Benchmarks()
{
using (var context = new TestContext())
{
context.Seed();
}
Context = new TestContext();
Context.Principals.Include(e => e.Dependent1s).Include(e => e.Dependent2s).Load();
Context.ChangeTracker.AutoDetectChangesEnabled = false;
AlternateKeyProperty = Context.Principals.EntityType.FindProperty(nameof(Principal.AltId))!;
ForeignKeyProperty = Context.Dependent2s.EntityType.FindProperty(nameof(Dependent2.PrincipalId))!;
NonKeyProperty = Context.Dependent2s.EntityType.FindProperty(nameof(Dependent2.NonKey))!;
}
[Benchmark]
public void DbSet_Find_by_primary_key()
{
var entity = Context.Principals.Find(501);
}
[Benchmark]
public void Search_entries_by_primary_key()
{
foreach (var entry in Context.ChangeTracker.Entries<Principal>())
{
if (entry.Entity.Id == 501)
{
return;
}
}
}
[Benchmark]
public void DbSet_Local_FindEntryByKey()
{
var entry = Context.Principals.Local.FindEntryByKey(501);
}
[Benchmark]
public void Search_entries_by_alternate_key()
{
foreach (var entry in Context.ChangeTracker.Entries<Principal>())
{
if (entry.Entity.AltId == 501)
{
return;
}
}
}
[Benchmark]
public void DbSet_Local_FindEntryByProperty_alternate_key()
{
var entry = Context.Principals.Local.FindEntryByProperty(AlternateKeyProperty, 501);
}
[Benchmark]
public void Search_entries_by_foreign_key()
{
var results = new List<Dependent2>();
foreach (var entry in Context.ChangeTracker.Entries<Dependent2>())
{
if (entry.Entity.PrincipalId == 501)
{
results.Add(entry.Entity);
}
}
}
[Benchmark]
public void DbSet_Local_GetEntriesByProperty_foreign_key()
{
var results = new List<Dependent2>();
foreach (var entry in Context.Dependent2s.Local.GetEntriesByProperty(ForeignKeyProperty, 501))
{
if (entry.Entity.PrincipalId == 501)
{
results.Add(entry.Entity);
}
}
}
[Benchmark]
public void Search_entries_by_non_key()
{
var results = new List<Dependent2>();
foreach (var entry in Context.ChangeTracker.Entries<Dependent2>())
{
if (entry.Entity.NonKey == 501)
{
results.Add(entry.Entity);
}
}
}
[Benchmark]
public void DbSet_Local_GetEntriesByProperty_non_key()
{
var results = new List<Dependent2>();
foreach (var entry in Context.Dependent2s.Local.GetEntriesByProperty(NonKeyProperty, 501))
{
if (entry.Entity.NonKey == 501)
{
results.Add(entry.Entity);
}
}
}
}
public class TestContext : DbContext
{
public DbSet<Principal> Principals { get; set; } = null!;
public DbSet<Dependent1> Dependent1s { get; set; } = null!;
public DbSet<Dependent2> Dependent2s { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseInMemoryDatabase("X");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Principal>()
.HasMany(e => e.Dependent2s)
.WithOne(e => e.Principal)
.HasPrincipalKey(e => e.AltId);
}
public void Seed()
{
for (var i = 1; i <= 1000; i++)
{
var principal = new Principal { Id = i, AltId = i };
for (var j = 1; j <= 20; j++)
{
principal.Dependent1s.Add(new Dependent1 { Id = (i * 20) + j, NonKey = i });
principal.Dependent2s.Add(new Dependent2 { Id = (i * 20) + j, NonKey = i });
}
Add(principal);
}
SaveChanges();
}
}
public class Principal
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int AltId { get; set; }
public List<Dependent1> Dependent1s { get; } = new();
public List<Dependent2> Dependent2s { get; } = new();
}
public class Dependent1
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public int? PrincipalId { get; set; }
public int NonKey { get; set; }
public Principal? Principal { get; set; }
}
public class Dependent2
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public int? PrincipalId { get; set; }
public int NonKey { get; set; }
public Principal? Principal { get; set; }
} |
ajcvickers
added
the
closed-fixed
The issue has been fixed and is/will be included in the release indicated by the issue milestone.
label
Dec 3, 2022
ajcvickers
changed the title
Lookup entities by primary key, alternate key, or foreign key
Lookup tracked entities by primary key, alternate key, or foreign key
Jan 5, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
area-change-tracking
area-dbcontext
closed-fixed
The issue has been fixed and is/will be included in the release indicated by the issue milestone.
type-enhancement
Using the internal indexes that the change tracker already builds for fixup. Currently this can only be done by iterating over all tracked entities.
Split off from #7391.
The text was updated successfully, but these errors were encountered: