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

TrackGraph stop tracking if current State is not set, but setting state throw InvalidOperationException #8226

Closed
cdie opened this issue Apr 19, 2017 · 3 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Milestone

Comments

@cdie
Copy link

cdie commented Apr 19, 2017

In our situation, we have to work with TrackGraph method because we have mapping between Domain and Persistence layer.

The fact is, in case of update, we look in local tracking entries to retrieve value and update it if necessary

        private void TrackGraph(EntityEntryGraphNode e)
        {
            if (e.Entry.IsKeySet)
            {
                var entry = Context.ChangeTracker.Entries().Where(m => m.Entity.GetType() == e.Entry.Entity.GetType())
                    .FirstOrDefault(m => m.Entity?.Equals(e.Entry.Entity) == true);
                if (entry == null) 
                {
                    e.Entry.State = EntityState.Modified; 
                }
                else
                {
                    var domainValues = GetPropertiesEvaluated(e.Entry.Entity);
                    var currentValues = GetPropertiesEvaluated(entry.Entity);
                    if (domainValues.Except(currentValues).Any())
                    {
                        entry.CurrentValues.SetValues(domainValues);
                        entry.State = EntityState.Modified;
                        if (entry.Entity is DbEntity ent)
                        {
                            ent.EditDate = DateTime.Now;
                        }
                    }
                    else
                    {
                        entry.State = EntityState.Unchanged;
                    }
                }
            }
            else
            {
                e.Entry.State = EntityState.Added;
            }
        }

In case of update, we enter the function with a Detached entity, retrieve the corresponding local instance and then updating it. However, because we're not setting the state of current entering entity in TrackGraph method, the TrackGraph method ends here ( https://github.com/aspnet/EntityFramework/blob/dev/src/EFCore/ChangeTracking/ChangeTracker.cs indicates that State should be different of Detached)

Is this possible to make Callback a Func<EntityEntryGraphNode, bool> to indicate continuation instead of relaying on the State ? Or maybe to have both method signatures ...

In my case, if I set State directly on the e.Entry, I've got and InvalidOperationException because Entity is currently tracked with the same key.

I've already tried to detach local entity, but the thing is, when I set state to my current entity, I have a InvalidOperationException at next node when calling Context.ChangeTracker.Entries().

Further technical details

EF Core version: 1.1.1
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10
IDE: VS 2017

@ajcvickers
Copy link
Member

@cdie We will consider this. As a workaround, you could use IEntityEntryGraphIterator directly. However, this is internal code, so be aware that we may make breaking changes to the API in any release.

@tonysneed
Copy link

tonysneed commented Dec 12, 2017

@ajcvickers I'm thinking that lifting IEntityEntryGraphIterator out of the Internal namespace (see my comment in #10517), might be a better solution that changing the parameter of TrackGraph from Action to Func, since that would be a breaking change on @the API. IEntityEntryGraphIterator.TraverseGraph already has a callback parameter that's a Func<EntityEntryGraphNode, bool>, and there's a TraverseGraphAsync method with the same Func parameter.

@ajcvickers ajcvickers modified the milestones: Backlog, 2.1.0 Feb 23, 2018
ajcvickers added a commit that referenced this issue Feb 23, 2018
Issues #10540 #8226

The overload required a new argument somewhere to avoid a breaking change, so I took the opportunity to add a state parameter to the API to allow state to be passed in without capturing.
@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Feb 23, 2018
@ajcvickers ajcvickers modified the milestones: 2.1.0-preview2, 2.1.0 Nov 11, 2019
@sjb-sjb
Copy link

sjb-sjb commented Sep 13, 2020

Asking for an improvement in the documentation (https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.changetracking.entityentrygraphnode-1.nodestate?view=efcore-3.1#Microsoft_EntityFrameworkCore_ChangeTracking_EntityEntryGraphNode_1_NodeState).

  • Need to state that the callback should return true to continue iteration to nodes reachable from the current node, or false to not iterate on nodes that are reachable from the current node (other than, presumably, nodes that have already been visited).
  • Need to explain that the state information is passed to the callback indirectly, in the NodeState property of the EntityEntryGraphNode<TState>.
  • Need to explain the difference between the Entry and SourceEntry properties of the EntityEntryGraphNode<TState>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Projects
None yet
Development

No branches or pull requests

4 participants