Skip to content
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

Reloading Data #13620

Open
wasabii opened this issue Oct 14, 2018 · 23 comments
Open

Reloading Data #13620

wasabii opened this issue Oct 14, 2018 · 23 comments

Comments

@wasabii
Copy link

wasabii commented Oct 14, 2018

I would very much like to know how to force data to reload in EF Core.

ReloadAsync on EntityEntry works fine. Though it sucks that you have to do it one at a time.

But what about Navigation collections? I have tried many ways to mess around with the CollectionEntry to no avail. Setting IsLoaded to false. Clearing current value. Setting CurrentValue manually to what I want.

Everything I try has at least one problem preventing it from working.

@wasabii
Copy link
Author

wasabii commented Oct 14, 2018

Okay, so, I've written a series of extension methods that navigate through the Entry graph and reload each component. Got it work right right. But, this is pretty terrible. Thousands of queries where one would suffice.

How about passing something like a MergeStrategy down through the query execution pipeline, which alters how data coming in is parsed into Entries? If it's set to Override, then it erases the contents of the Entry's current values, and sets it to Loaded + NotModified?

And then an addition to LoadAsync which accepts a MergeStrategy?

This would be incredibly helpful.

@ajcvickers
Copy link
Contributor

@wasabii The reason we haven't implemented this with higher priority is because a single context instance is intended to be used for a single unit-of-work. This usually results in no, or very limited, need to refresh existing entities. Any conflicts that happen while the unit-of-work is being executed are either handled as a last-one-wins, or with optimistic concurrency patterns to resolve the conflicts.

That being said, it's still useful to have an issue on the backlog to track adding better support for doing this when it is needed, so leaving this issue open to track that work.

@wasabii
Copy link
Author

wasabii commented Oct 15, 2018

Doesn't jive with using a DbContext per DI scope, however. In this mode of operation, there is no way to get rid of the DBContext for the entire scope, replace all users of it within that scope, and get them refreshed entity entries.

So my specific issue is that I have to do operations outside of EF, but within the same transaction and unit of work. Specifically, SQL bulk loader, execute a few stored procedures, etc.

@GF-Huang
Copy link

Any progress of reload collection ?

@GF-Huang
Copy link

GF-Huang commented Jul 16, 2019

To be frank, in some scenarios, when optimistic concurrency occurs, the retry code is exactly the same as normal logic. This means that I have to copy the code that inside try block to the catch block if I don't use Polly.

If I can reload the entire context or clear the entire context tracking object (cache), then I can wrap my whole business code block in Polly.

You can say: you can create a new dbContext each retry.
But this makes DI (AddDbContextPool) meaningless.

I can't even find a Reload for CollectionEntry.

@ajcvickers
Copy link
Contributor

@greatfirewall This issue is in the Backlog milestone. This means that it is not going to happen for the 3.0 release. We will re-assess the backlog following the 3.0 release and consider this item at that time. However, keep in mind that there are many other high priority features with which it will be competing for resources.

@GF-Huang
Copy link

@ajcvickers Thanks your reply so quick.

Can you give me a solution how to reload a navigation collection in EF Core 2.x ?
I ask a quetion on stackoverflow describe my question details.
Thank you !

@ajcvickers
Copy link
Contributor

@greatfirewall The answer on Stack Overflow is reasonable.

@GF-Huang
Copy link

Yes, I try it and works well. :)

@IvanZheng
Copy link

@ajcvickers I use the following code to reset current dbcontext.
(dbContext as IDbContextDependencies).StateManager?.ResetState();
Just like @greatfirewall said it's meaningless to create a new dbContext with DI (AddDbContextPool) . But it's not recommend to use StateManager directly, Is there a better way to reset dbcontext's state?

@AndriySvyryd
Copy link
Member

@IvanZheng Resetting the context is tracked by #15577. A better DI integration is tracked by #18575.

@ajcvickers
Copy link
Contributor

@IvanZheng Why are you using DbContext pooling?

@IvanZheng
Copy link

IvanZheng commented Oct 25, 2019

@ajcvickers I use DbContext pool to improve performance and it's recommend by most guides. I use AOP to re-execute the whole application service case when optimistic concurrency conflict occurs. I need to reset the current DI DbContext instance after catching optimistic concurrency exception.

@ajcvickers
Copy link
Contributor

@IvanZheng Could you point me to the places where it is recommended? (It rarely has a measurable difference on performance; I would also be interested in seeing numbers if is providing a noticeable performance improvement in a real-world app.)

@GF-Huang
Copy link

GF-Huang commented Oct 25, 2019

Unless the official document is deceptive 😄
https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.0#dbcontext-pooling

image

@IvanZheng
Copy link

I think the key is that DbContextPool saves some of cost of initialization of DbContext instance. Since DbContext is resolved by DI Container, I need to reset the DbContext when re-executing the whole application case whatever the DbContextPool used or not.

@GF-Huang
Copy link

Any progress after 3 years?

@AndriySvyryd
Copy link
Member

Related to #16491

@GF-Huang
Copy link

4 years.

@ajcvickers
Copy link
Contributor

@GF-Huang If this is something you need, then make sure to vote (👍) for it. This issue currently has no votes.

@GF-Huang
Copy link

@GF-Huang If this is something you need, then make sure to vote (👍) for it. This issue currently has no votes.

I'm not sure if I really need it, in other words why so many people don't need this feature? Is there some other better way to replace this feature that I don't know?

@ajcvickers
Copy link
Contributor

@GF-Huang The thread above contains several suggestions as well as a link to Stack Overflow. Is there something that isn't covered?

@Int32Overflow
Copy link

Int32Overflow commented Jul 8, 2024

@ajcvickers Thanks your reply so quick.

Can you give me a solution how to reload a navigation collection in EF Core 2.x ? I ask a quetion on stackoverflow describe my question details. Thank you !

Can anyone tell me if this trick from StackOverflow still works with the latest EFC 8?

An SQL is sent to the database but unfortunately the collection is empty afterwards. If I execute this identical SQL statement manually, the database tool returns several pieces of data. This means for me that the SQL statement fits, but for whatever reason, the EFC does not load it correctly.

I like to reload a entity with the sub collection. Here an example:

public class PersonEntity 
{
    public long Id {get;set;}
    public string FirstName {get; set;}
    public string LastName {get;set;}
    public virtual IListTelefonNumberEntity> PhoneNumbers {get;set;}
}
public class PhoneNumberEntity 
{
    public long PersonId {get;set;}
    public string PhoneNumber {get;set;}
}

public async Task ReloadTest(PersonEntity entity)
{
      var entry = dbContext.Entry(entity);
      await entry.ReloadAsync();
      await entry.Collection(p => p.PhoneNumbers).ReloadAsync();
}

    public static Task ReloadAsync<TEntity, TRelated>(this CollectionEntry<TEntity, TRelated> source, CancellationToken cancellationToken = default)
        where TEntity : class
        where TRelated : class
    {
        if (source.CurrentValue != null)
        {
            foreach (var item in source.CurrentValue.ToList())
                source.EntityEntry.Context.Entry(item).State = EntityState.Detached;
            source.CurrentValue = null;
        }
        source.IsLoaded = false;
        return source.LoadAsync(cancellationToken);
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants