Skip to content

RC2: Regression with Parent/Child relationship #5674

@rwg0

Description

@rwg0

Steps to reproduce

Use the following code to reproduce:

    class Program
    {
        static void Main(string[] args)
        {
            if (File.Exists("test.db"))
                File.Delete("test.db");

            using (var context = new WidgetContext())
            {
                context.Database.Migrate();
            }

            using (var context = new WidgetContext())
            {
                for (int i = 0; i < 10; i++)
                {
                    var w = new Widget();
                    context.Widgets.Add(w);
                }

                context.SaveChanges();
            }

            using (var context = new WidgetContext())
            {
                var widgets = context.Widgets.ToList();
                widgets[0].ParentWidget = widgets[1];
                context.SaveChanges();
            }

            using (var context = new WidgetContext())
            {
                var widgets = context.Widgets.ToList();
                try
                {
                    Console.WriteLine(widgets[1].ChildWidgets.Count);
                }
                catch (Exception e)
                {
                    Console.WriteLine("oops, didn't connect childwidgets collection.");
                    Console.WriteLine(e);
                }
                widgets[0].ParentWidget = widgets[2];
                try
                {
                    context.SaveChanges();
                    Console.WriteLine("Saved change of parent.");
                }
                catch (Exception e)
                {
                    Console.WriteLine("oops, couldn't alter the parent Id");
                    Console.WriteLine(e);
                }
            }
        }
    }

    class WidgetContext : DbContext
    {
        public DbSet<Widget> Widgets { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite("Filename=test.db");
        }
    }

    public class Widget
    {
        public int Id { get; set; }

        public int? ParentWidgetId { get; set; }

        [InverseProperty(nameof(ChildWidgets))]
        [ForeignKey(nameof(ParentWidgetId))]
        public Widget ParentWidget { get; set; }


        [InverseProperty(nameof(ParentWidget))]
        public List<Widget> ChildWidgets { get; set; }
    }

Add nuget packages for appropriate version of EntityFramework.Sqlite/EntityFrameworkCore.Sqlite and EntityFramework.Commands/EntityFrameworkCore.Tools.

Create an initial migration.

The issue

On RC2, the ChildWidgets collection on each Widget when loading the entire table, so the line
Console.WriteLine(widgets[1].ChildWidgets.Count);
throws a NullReferenceException. This works correctly on RC1.

Additionally, changing the ParentWidget of a Widget that already has a parent set fails when the changes are saved to the database with the following exception.

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.RemoveFromCollectionSnapshot(IPropertyBase propertyBase, Object removedEntity)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.RemoveFromCollection(InternalEntityEntry entry, INavigation navigation, IClrCollectionAccessor collectionAccessor, Object value)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.KeyPropertyChanged(InternalEntityEntry entry, IProperty property, IReadOnlyList`1 containingPrincipalKeys, IReadOnlyList`1 containingForeignKeys, Object oldValue, Object newValue)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.KeyPropertyChanged(InternalEntityEntry entry, IProperty property, IReadOnlyList`1 keys, IReadOnlyList`1 foreignKeys, Object oldValue, Object newValue)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectKeyChange(InternalEntityEntry entry, IProperty property)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.PropertyChanged(InternalEntityEntry entry, IPropertyBase propertyBase, Boolean setModified)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.PropertyChanged(InternalEntityEntry entry, IPropertyBase property, Boolean setModified)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetProperty(IPropertyBase propertyBase, Object value, Boolean setModified)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.SetForeignKeyProperties(InternalEntityEntry dependentEntry, InternalEntityEntry principalEntry, IForeignKey foreignKey, Boolean setModified)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.NavigationReferenceChanged(InternalEntityEntry entry, INavigation navigation, Object oldValue, Object newValue)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.NavigationReferenceChanged(InternalEntityEntry entry, INavigation navigation, Object oldValue, Object newValue)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectNavigationChange(InternalEntityEntry entry, INavigation navigation)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectNavigationChanges(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectRelationshipChanges(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectChanges(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectChanges(IStateManager stateManager)
   at Microsoft.EntityFrameworkCore.DbContext.TryDetectChanges(IStateManager stateManager)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()

Again, this works correctly on RC1. I suspect this may be a consequence of the ChildWidget list being left null - so a maybe just another symptom of the first problem.

Further technical details

EF Core version: 1.0.0-rc2-final
Operating system: Windows 10 Pro x64
Visual Studio version: VS2015 update 2

Other details about my project setup: Console App, Target : .NET 4.5.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions