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

SavingChanges in EF Core 5.0 thrown System.NotSupportedException: #22841

Closed
alraseen opened this issue Sep 28, 2020 · 14 comments
Closed

SavingChanges in EF Core 5.0 thrown System.NotSupportedException: #22841

alraseen opened this issue Sep 28, 2020 · 14 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@alraseen
Copy link

After I upgraded form ef core 3.1 to ef core 5.0.0-rc , I got a System.NotSupportedException: 'This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.'. it happened when I save changes after removing an entity

@ajcvickers
Copy link
Member

@loveprogrammin Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

@alraseen
Copy link
Author

alraseen commented Sep 29, 2020

this is the classes

public class Level : BindableBase
{

    public Level()
    {
        LevelOne = new ObservableCollection<LevelOne>();
    }
    
    public Guid Guid { get; set; }

    private int code;
    public int Code
    {
        get { return code; }
        set { SetProperty(ref code, value); }
    }
    private string name;
    public string Name
    {
        get { return name; }
        set { SetProperty(ref name, value); }
    }

    private ObservableCollection<LevelOne> levelOne;
    public ObservableCollection<LevelOne> LevelOne
    { 
        get { return levelOne; }
        set { SetProperty(ref levelOne, value); }
    }
}

and the second class

 public class LevelOne :BindableBase
 {

    public LevelOne()
    {
        LevelTwo = new ObservableCollection<LevelTwo>();
    }
    public Guid Guid { get; set; }
    public Guid LevelId { get; set;}
    private int code;
    public int Code
    {
        get { return code; }
        set { SetProperty(ref code, value); }
    }
    private string name;
    public string Name
    {
        get { return name; }
        set { SetProperty(ref name, value); }
    }

    public Level Level { get; set; }

    private ObservableCollection<LevelTwo> levelTwo;
    public ObservableCollection<LevelTwo> LevelTwo
    {
        get { return levelTwo; }
        set { SetProperty(ref levelTwo, value); }
    }
}

and the DbContext

public class AppsContext : DbContext
{
    public DbSet<Level> Levels { get; set; }

    public DbSet<LevelOne> LevelOnes { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Initial Catalog=TestDB;Trusted_Connection=true;Server=(localDB)\\MSSQLLocalDB");
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
       modelBuilder.ApplyConfiguration(new LevelConfiguration());
        modelBuilder.ApplyConfiguration(new LevelOneConfiguration());
    }
}

and the LevelConfiguration is

public class LevelConfiguration : IEntityTypeConfiguration<Level>
{

    public void Configure(EntityTypeBuilder<Level> builder)
    {
        builder.ToTable("Level");
        builder.HasKey(s => s.Guid);
        builder.HasIndex(s => s.Code).IsUnique();
        builder.HasIndex(e => e.Name).IsUnique();
        builder.Property(e => e.Name).IsRequired();
    }
}

and the LevelOneConfiguration is

public class LevelOneConfiguration : IEntityTypeConfiguration<LevelOne>
{
    public void Configure(EntityTypeBuilder<LevelOne> builder)
    {
        builder.ToTable("LevelOne");
        builder.HasKey(e => e.Guid);

        builder.HasIndex(e => e.Code).IsUnique();

        builder.HasIndex(e => e.Name).IsUnique();

        builder.Property(e => e.Name).IsRequired();

        builder.HasOne(d => d.Level)
            .WithMany(p => p.LevelOne)
            .HasForeignKey(d => d.LevelId)
            .OnDelete(DeleteBehavior.Restrict)
            ; 
    }
}

I hope that will help

@ajcvickers
Copy link
Member

@loveprogrammin I don't think the issue is related to your EF configuration or model. I don't think there will be much we can do without the executable code that sets up the the appropriate situation to generates the exception.

@AndriySvyryd
Copy link
Member

EF Team Triage: This issue is still lacking enough information for us to be able to effectively triage it. Once you provide a small, runnable project or post a small, runnable code listing that reproduces what you are seeing we can investigate and reopen this issue.

@alraseen
Copy link
Author

alraseen commented Oct 20, 2020

this is a runnable project https://1drv.ms/u/s!ApQ9UD_gEQ2qgbEjko4z-HIvUkWaiQ?e=ulXh0y

Make sure before you run the application to uncomment the lines inside LoadAsync() method in MainWindowViewModel to add the data to the Database. After that run the app and try to remove last subchild in the treeview using the contextMenu

@ajcvickers
Copy link
Member

@dotnet/efteam This requires Windows to repro. Can somebody try?

@AndriySvyryd
Copy link
Member

This is a consequence of #10164

@loveprogrammin Change the SaveChangesAsync() method to this:

public async Task SaveChangesAsync()
{            
    await context.SaveChangesAsync(acceptAllChangesOnSuccess: false);
    context.ChangeTracker.AcceptAllChanges();
}

This will make EF modify the model collections on the current (Dispatcher) thread.

@AndriySvyryd AndriySvyryd added closed-no-further-action The issue is closed and no further action is planned. and removed closed-could-not-reproduce labels Oct 21, 2020
@alraseen
Copy link
Author

alraseen commented Oct 21, 2020

This is a consequence of #10164

@loveprogrammin Change the SaveChangesAsync() method to this:

public async Task SaveChangesAsync()
{            
    await context.SaveChangesAsync(acceptAllChangesOnSuccess: false);
    context.ChangeTracker.AcceptAllChanges();
}

This will make EF modify the model collections on the current (Dispatcher) thread.

Thanks it's work 😀

However, if you try removing entity and its throws exception , nothing will be save and that is the right. After that .if I try to remove another entity and on exception thrown ,saving changes will remove both entity the one that had exception and the other one with no exception.

@ajcvickers ajcvickers reopened this Oct 21, 2020
@ajcvickers
Copy link
Member

@AndriySvyryd reopened to discuss if we should add additional documentation here.

@AndriySvyryd
Copy link
Member

Yes, we should add a note to the WPF tutorial

@alraseen
Copy link
Author

I think removing entity is another problem
In same project when I try to remove parent item, it throws exception and that's ok because the required relationship. Thus, removing the last-Child item of tree will remove it with the parent even if parent has other children.

@roji
Copy link
Member

roji commented Oct 21, 2020

We should also add some documentation to our async programming page (I can do that).

@alraseen
Copy link
Author

I not sure if this going to produce other problems but I reset the context before removing item and it works
public void ResetContext() { context = new AppsContextFactory().CreateDbContext(null); }

@AndriySvyryd
Copy link
Member

Filed dotnet/EntityFramework.Docs#2801

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported
Projects
None yet
Development

No branches or pull requests

3 participants