1

I would like if there is a way to trigger an object hierachy's lazy load after it has been added in the cache following an insert.

If I insert an object only providing it the foreign keys ids and try to request it right after, none of these properties / collections are retrieved.

Example:

            _dbContext.Set<MYTYPE>().Add(myObject);
            await _dbContext.SaveChangesAsync(ct);
            _dbContext.Entry(myObject).Collection(c => c.SomeCollection).Load();
            _dbContext.Entry(myObject).Reference(c => c.Property1).Load();
            _dbContext.Entry(myObject.Property1).Reference(c => c.NestedProperty).Load();
            _dbContext.Entry(myObject).Reference(c => c.Property2).Load();
            _dbContext.Entry(myObject).Collection(c => c.SomeCollection2).Load();
            _dbContext.Entry(myObject).Reference(c => c.Property3).Load();
            _dbContext.Entry(myObject).Reference(c => c.Property4).Load();
            _dbContext.Entry(myObject.Property4).Reference(c => c.SomeOtherNestedProperty).Load();
            _dbContext.Entry(myObject).Reference(c => c.Property5).Load();
            _dbContext.Entry(myObject).Reference(c => c.Property6).Load();

            return _dbContext.Set<MYTYPE>().Where(x => x.Id == myObject.Id); 

Unless I do all the Load() (having to nest into several layers sometimes ...), I can't have any of the sub properties properly lazy loaded.

Note: doing

_dbContext.Entry(myObject).Reload()

or

_dbContext.Entry(myObject).State = EntityState.Detached;

doesn't work.

Any idea? Because I have several cases like this, with HEAVY object nesting, and it feels really bad to have to do all the loads manually.

Thanks.

David Specht
  • 7,784
  • 1
  • 22
  • 30
Thomas KiTe Trentin
  • 600
  • 1
  • 5
  • 19
  • Then why not trying without lazy load ? Eagerly loading would not be an option ? – Antoine Pelletier Jan 30 '20 at 19:26
  • The thing is it has the entity I added in cache, so whatever I do it does not load the other properties without explicit load. which make no sense, even if I invalidate the entity ... – Thomas KiTe Trentin Jan 30 '20 at 19:47
  • Ho wait, all that is because you are putting foreign key as integer only before inserting and saving instead of linking the whole object, understand ? I'll post an answer to explain. – Antoine Pelletier Jan 30 '20 at 19:52
  • Also, I recommend you take a look at this question's answer https://stackoverflow.com/questions/40729137/why-are-foreign-keys-in-ef-code-first-marked-as-virtual/40729675#40729675 – Antoine Pelletier Jan 30 '20 at 20:30

2 Answers2

1

The thing is, if you try to add some line using only the integer as a foreign key like below :

db.tablename.Add(new tablename{

            name = "hello",
            FK_IdofanotherTable = 5
            });
db.SaveChanges();

Then entity does not care about linking the object immediately, you won't be able to access the linked object as a property.

This is how it's actually done in modern Entity Framework :

var TheActualCompleteObject = db.AnotherTable.First(t => t.id == 5);

db.tablename.Add(new tablename{

            name = "hello",
            AnotherTable = TheActualCompleteObject
            });
db.SaveChanges();

So... basically, you will have loaded the object anyway, it's not gonna make anything faster, but it will be more consistant. You will be able to navigate through foreign keys properties.

If this is not possible, then you will have to query back AFTER SaveChanges to retrieve your object AND have access to foreign properties (eagerly loading them, of course, or else it's the same disaster)

Exemple :

       _dbContext.Configuration.LazyLoadingEnabled = false;
       _dbContext.Set<MYTYPE>().Add(myObject);
       await _dbContext.SaveChangesAsync(ct);
       var v = _dbContext.First(t => t.id == myObject.id);
       var fk_prop = v.Property1;
Antoine Pelletier
  • 3,164
  • 3
  • 40
  • 62
0

I also found no easy way around this. The following might make it simpler...

public static void Reset(this DbContext context)
    {
        var entries = context.ChangeTracker
                            .Entries()
                            .Where(e => e.State != EntityState.Unchanged)
                            .ToArray();
        foreach (var entry in entries) 
        { 
            switch (entry.State) 
            { 
                case EntityState.Modified: 
                    entry.State = EntityState.Unchanged; 
                    break; 
                case EntityState.Added: 
                    entry.State = EntityState.Detached; 
                    break; 
                case EntityState.Deleted: 
                    entry.Reload(); 
                    break; 
            } 
        }
    }

Hope this helps!

JS

jstougas
  • 1
  • 2