C
C#8mo ago
UltraWelfare

❔ EFCore Change Tracker Confusion

Assuming a entity Order with a relationship to entity Table
var order = new Order() {
...
TableId = requestTableId
};
db.Orders.Add(order);
await db.SaveChangesAsync();

var sameOrder = await db.Orders.Include(o => o.Table).Where(o => order.Id).SingleAsync();
var order = new Order() {
...
TableId = requestTableId
};
db.Orders.Add(order);
await db.SaveChangesAsync();

var sameOrder = await db.Orders.Include(o => o.Table).Where(o => order.Id).SingleAsync();
Shouldn't the "sameOrder" be fetched from the tracker and do a single query for the table only? Since it's already being tracked.. Because in my application I'm seeing it fetches the whole order from the start... Unless there's some kinda of rule about relationships that I couldn't find
12 Replies
UltraWelfare
UltraWelfare8mo ago
Seems like the answer relies here
No description
Jimmacle
Jimmacle8mo ago
what if the order was modified in the database between saving it and getting it back? the change tracker tracks local modifications, it's not a caching layer per se
UltraWelfare
UltraWelfare8mo ago
I read somewhere that reading an entity that already exists in the changetracker, returns the entity from the changetracker that is especially true with the "Include" there's a pitfall too Seems like it only works with Find
public class Order
{
public int Id { get; set; }
public string Title { get; set; }

public int TableId { get; set; }
public Table Table { get; set; }
}

public class Table
{
public int Id { get; set; }
public string Title { get; set; }

public List<Order> Orders { get; set; } = new();
}

public class TestContext : DbContext
{
public TestContext(){ }

public TestContext(DbContextOptions<TestContext> options)
: base(options){ }

public DbSet<Order> Orders { get; set; }

public DbSet<Table> Tables { get; set; }
}

class Program
{
static void Main(string[] args)
{
Console.WriteLine("This is an example of using EF Core InMemory Database");
Console.WriteLine("======================================================");
Console.WriteLine("");

var options = new DbContextOptionsBuilder<TestContext>()
.UseSqlite("DataSource=test.db")
.LogTo(Console.WriteLine)
.Options;
var ctxOld = new TestContext(options);
ctxOld.Database.EnsureCreated();

ctxOld.Tables.Add(new Table() { Id = 1, Title = "a" });
ctxOld.SaveChanges();
ctxOld.Dispose();

var ctx = new TestContext(options);

var order = new Order() {
Title = "Order Title",
TableId = 1

};

ctx.Orders.Add(order);
ctx.SaveChanges();

ctx.Orders.Single(o => o.Id == 1);
ctx.Orders.Single(o => o.Id == 1);
}
}
public class Order
{
public int Id { get; set; }
public string Title { get; set; }

public int TableId { get; set; }
public Table Table { get; set; }
}

public class Table
{
public int Id { get; set; }
public string Title { get; set; }

public List<Order> Orders { get; set; } = new();
}

public class TestContext : DbContext
{
public TestContext(){ }

public TestContext(DbContextOptions<TestContext> options)
: base(options){ }

public DbSet<Order> Orders { get; set; }

public DbSet<Table> Tables { get; set; }
}

class Program
{
static void Main(string[] args)
{
Console.WriteLine("This is an example of using EF Core InMemory Database");
Console.WriteLine("======================================================");
Console.WriteLine("");

var options = new DbContextOptionsBuilder<TestContext>()
.UseSqlite("DataSource=test.db")
.LogTo(Console.WriteLine)
.Options;
var ctxOld = new TestContext(options);
ctxOld.Database.EnsureCreated();

ctxOld.Tables.Add(new Table() { Id = 1, Title = "a" });
ctxOld.SaveChanges();
ctxOld.Dispose();

var ctx = new TestContext(options);

var order = new Order() {
Title = "Order Title",
TableId = 1

};

ctx.Orders.Add(order);
ctx.SaveChanges();

ctx.Orders.Single(o => o.Id == 1);
ctx.Orders.Single(o => o.Id == 1);
}
}
using linq operators will always do a db roundtrip even with or without include
Jimmacle
Jimmacle8mo ago
yes, i wouldn't want it to work any other way
UltraWelfare
UltraWelfare8mo ago
it works like that on include though thats strange if you query something and include orderby then query it again and do the same thing the include will not work
Jimmacle
Jimmacle8mo ago
define "not work"
UltraWelfare
UltraWelfare8mo ago
literally, it will ignore it it's in the ms documentation https://learn.microsoft.com/en-us/ef/core/querying/related-data/eager#filtered-include look at Caution
var orders = context.Orders.Where(o => o.Id > 1000).ToList();

// customer entities will have references to all orders where Id > 1000, rather than > 5000
var filtered = context.Customers.Include(c => c.Orders.Where(o => o.Id > 5000)).ToList();
var orders = context.Orders.Where(o => o.Id > 1000).ToList();

// customer entities will have references to all orders where Id > 1000, rather than > 5000
var filtered = context.Customers.Include(c => c.Orders.Where(o => o.Id > 5000)).ToList();
Jimmacle
Jimmacle8mo ago
i have never used a filtered include
UltraWelfare
UltraWelfare8mo ago
yeah I accidently did it... and then I assumed tracked entities are always returned Stay away from it
Jimmacle
Jimmacle8mo ago
yeah that syntax is wrong if you're just trying to get orders nvm, read wrong syntax is still wrong either way
UltraWelfare
UltraWelfare8mo ago
Yep, in my case when i did a filtered include i was trying just to orderby the collection but it didn't work and it was this " bug " so I assumed changetracker always returns the tracked entities seems like not the case unless you're using Find(key) this seems to always return the tracked entity if found anything else just does a db roundtrip
Accord
Accord8mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server
More Posts