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

Exception replacing multi-level relationship in EF7 #30135

Closed
iheb719 opened this issue Jan 25, 2023 · 3 comments · Fixed by #30204
Closed

Exception replacing multi-level relationship in EF7 #30135

iheb719 opened this issue Jan 25, 2023 · 3 comments · Fixed by #30204
Labels
area-change-tracking closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Milestone

Comments

@iheb719
Copy link

iheb719 commented Jan 25, 2023

Ask a question

I have the following model

public partial class Parent
{
    public int IdParent { get; set; }

    public virtual ICollection<FirstChild> FirstChild{ get; set; } = new List<FirstChild>();
}

public partial class FirstChild
{
    public int IdFirstChild { get; set; }

    public virtual ICollection<SecondChild> SecondChild { get; set; } = new List<SecondChild>();
}

public partial class SecondChild 
{
    public int IdSecondChild  { get; set; }

    public virtual ICollection<ThirdChild> ThirdChild{ get; set; } = new List<ThirdChild>();
}

public partial class ThirdChild
{
    public int IdThirdChild { get; set; }

    public String SomeProperty{ get; set; }
}

I update Parent with all it's relationships it this way :

var parentDB = _context.Parent.Single(x => x.IdParent == {id})
.Include(x => x.FirstChild)
.ThenInclude(x => x.SecondChild)
.ThenInclude(x => x.ThirdChild);

parentDb.FirstChild = {newCollectionValuesList}

_context.SaveChanges();

This works with EF Core 6 :

  • If in {newCollectionValuesList}, there is an element that already exists in parentDb.FirstChild (same ID), it get updated (with all its hierarchy)
  • If if does not exists, it will be added
  • If it exists but was not specified in {newCollectionValuesList}, it get deleted

When I upgraded to EF Core 7, I started to have this error :

The instance of entity type 'SecondChild' cannot be tracked because another instance with the key value '{IdSecondChild: XXXX}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached

I tried to add .AsNoTracking() in the query to resolve this, but my entities won't be updated

I don't want to loop manually through all the relationship and manually add the conditions to update the child elements

I didn't find anything related to that in What's new in EF7 nor in Breaking changes in EF7

This is a sample project with integration tests to reproduce the problem

Is this a bug ? because it works in EF6
Same result using dotnet6 and dotnet7

@ajcvickers
Copy link
Contributor

Note for triage: I am able to reproduce this. In 6.0, the existing instances are cascade-deleted before the new instances are tracked. In 7.0, the identity conflict happens before the cascade delete. Could be related to #30122.

FirstChild (Shared) {IdFirstChild: 11} Added
  IdFirstChild: 11 PK
  FirstChildName: 'firstChild1'
  IdParent: 1 FK
  IdParentNavigation: {IdParent: 1}
  SecondChild: [{IdSecondChild: 111}, {IdSecondChild: 111}]
FirstChild (Shared) {IdFirstChild: 11} Deleted
  IdFirstChild: 11 PK
  FirstChildName: 'firstChild1'
  IdParent: 1 FK
  IdParentNavigation: <null>
  SecondChild: [{IdSecondChild: 111}]
FirstChild {IdFirstChild: 12} Added
  IdFirstChild: 12 PK
  FirstChildName: 'firstChild2'
  IdParent: 1 FK
  IdParentNavigation: {IdParent: 1}
  SecondChild: []
Parent {IdParent: 1} Unchanged
  IdParent: 1 PK
  ParentName: 'parent'
  FirstChild: [{IdFirstChild: 11}, {IdFirstChild: 12}]
SecondChild (Shared) {IdSecondChild: 111} Added
  IdSecondChild: 111 PK
  IdFirstChild: 11 FK
  SecondChildName: 'secondChild1'
  IdFirstChildNavigation: {IdFirstChild: 11}
  ThirdChild: [{IdThirdChild: 1111}, {IdThirdChild: 1111}]
SecondChild (Shared) {IdSecondChild: 111} Deleted
  IdSecondChild: 111 PK
  IdFirstChild: 11 FK
  SecondChildName: 'secondChild1'
  IdFirstChildNavigation: {IdFirstChild: 11}
  ThirdChild: [{IdThirdChild: 1111}]
ThirdChild (Shared) {IdThirdChild: 1111} Added
  IdThirdChild: 1111 PK
  IdSecondChild: 111 FK
  ThirdChildName: 'thirdChild1'
  IdSecondChildNavigation: {IdSecondChild: 111}
ThirdChild (Shared) {IdThirdChild: 1111} Deleted
  IdThirdChild: 1111 PK
  IdSecondChild: 111 FK
  ThirdChildName: 'thirdChild1'
  IdSecondChildNavigation: {IdSecondChild: 111}

@ajcvickers
Copy link
Contributor

@iheb719 Workaround is to for the deletion before replacing the collection:

public void UpdateParentChild(Parent parentUpdate)
{
    var existingParent = _context.Parent.Local.FirstOrDefault(x => x.IdParent == parentUpdate.IdParent);
    existingParent?.FirstChild.Clear();
    _context.ChangeTracker.DetectChanges();
    
    var parentBd = _context.Parent
        .Include(x => x.FirstChild)
        .ThenInclude(x => x.SecondChild)
        .ThenInclude(x => x.ThirdChild)
        .Single(x => x.IdParent == parentUpdate.IdParent);

    parentBd.ParentName = parentUpdate.ParentName;
    parentBd.FirstChild = parentUpdate.FirstChild;

    _context.SaveChanges();
}

@iheb719
Copy link
Author

iheb719 commented Jan 26, 2023

Thanks @ajcvickers the workaround is working

@ajcvickers ajcvickers added this to the 7.0.x milestone Jan 28, 2023
@ajcvickers ajcvickers self-assigned this Jan 28, 2023
ajcvickers added a commit that referenced this issue Feb 3, 2023
Fixes #30122
Fixes #30135

EF7 contained some new calls to local `DetectChanges`. This resulted in re-entrance into `DetectChanges` for some types of graphs. This change prevents that.
@ajcvickers ajcvickers removed this from the 7.0.x milestone Feb 3, 2023
@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 3, 2023
@ajcvickers ajcvickers reopened this Feb 3, 2023
@ajcvickers ajcvickers added this to the 7.0.x milestone Feb 9, 2023
ajcvickers added a commit that referenced this issue Feb 9, 2023
Fixes #30122
Fixes #30135

EF7 contained some new calls to local `DetectChanges`. This resulted in re-entrance into `DetectChanges` for some types of graphs. This change prevents that.
ajcvickers added a commit that referenced this issue Feb 14, 2023
Fixes #30122
Fixes #30135

EF7 contained some new calls to local `DetectChanges`. This resulted in re-entrance into `DetectChanges` for some types of graphs. This change prevents that.
@ajcvickers ajcvickers modified the milestones: 7.0.x, 7.0.4 Feb 14, 2023
@ajcvickers ajcvickers changed the title Replace multi-level relationship in Entity Framework Core 6 vs 7 Exception replacing multi-level relationship in EF7 Mar 14, 2023
@ajcvickers ajcvickers removed their assignment Aug 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-change-tracking closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants