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

Can't find how to add to an owned collection without modifying the rest of the items #20803

Closed
mooseburger opened this issue May 1, 2020 · 8 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@mooseburger
Copy link

mooseburger commented May 1, 2020

Bug: An unmodified owned entity in a collection will still enter modified state if Update is called on its parent entity.

I have an owned type called Comment. Several entities in my application have collections of Comments. I have a requirement that a Comment can never be modified. I thought to use the DbContext.ChangeTracker to throw an exception whenever a comment is in the Modified state. But the problem is that if Update is called on the parent of the comment collection, every comment that was there is changed to Modified state, even if no change actually occurred on the comment.

I got around this by using Attach on the parent entity, instead of Update, then setting the resulting EntityEntry's State to Modified. This fixed the issue with comments, but it broke another owned entity, Address . There are entities that have two Address references (postal and residential), but with the Attach workaround, these addresses have stopped updating. Looking at the docs, I can't figure out how to implement this comment requirement using EF core. It appears the ChangeTracker is useless for this purpose as far as I can tell.

Steps to reproduce

Further technical details

EF Core version: 3.1
Database provider: (e.g. Microsoft.EntityFrameworkCore.SqlServer)
Target framework: (e.g. .NET Core 3.0)
Operating system: Windows 10
IDE: (e.g. Visual Studio 2019 16.5.4)

@ajcvickers
Copy link
Member

@mooseburger There are different ways of handling graphs of disconnected entities, as discussed in the docs: https://docs.microsoft.com/en-us/ef/core/saving/disconnected-entities. It's hard to know without actual code, but it seems like for your case using Attach on the parent followed by setting state on the children should work. Alternately, you could use TrackGraph to explicitly set the state of each entity while it is being tracked.

These blog posts may also be useful:
https://blog.oneunicorn.com/2020/01/17/dontcallupdate/
https://blog.oneunicorn.com/2020/01/18/docallupdate/

@mooseburger
Copy link
Author

mooseburger commented May 1, 2020

So I have this:

public class Member
 {
      ...
     public ICollection<Comment> Comments { get; set; }
     ....
}

[Owned]
public class Comment 
{
       public int Id { get; set; }
       .... 
}

And this is configured like this:

private void ConfigureOwnedCollections(ModelBuilder modelBuilder)
 {
            modelBuilder.Entity<Member>().OwnsMany(e => e.Comments, c => {
                c.WithOwner().HasForeignKey("OwnerId");
                c.Property<int>("Id");
                c.HasKey("Id");
            });
            ....
}

but it seems like for your case using Attach on the parent followed by setting state on the children should work.

But then, that leaves it up to me to determine which (if any) of the children, were modified no? There's no way to have ChangeTracker do that?

@ajcvickers
Copy link
Member

@mooseburger If you want control over that, then use context.ChanteTracker.TrackGraph().

@mooseburger
Copy link
Author

It's not that I wish I had control over it, it's that I wish EF Core would do it for me. TrackGraph appears to leave it up to me to devise a callback in which to determine whether a comment has been modified. I decided to do something like this within an override of SaveChangesAsync:

foreach (var modified in ChangeTracker.Entries().Where(e => e.Entity is Comment && e.State == EntityState.Modified)) {
             modified.State = EntityState.Unchanged;
}

This prevents modification of comments, app-wide, but I would have preferred to throw an exception.

@ajcvickers
Copy link
Member

@mooseburger If there is some way that EF is behaving differently than your expectations, then please attach a small, runnable project or post a small, runnable code listing that reproduces this behavior. We're happy to consider enhancements, but we need to be talking about a concrete behavior with just code snippets.

@mooseburger
Copy link
Author

It's just that when I saw something called ChangeTracker, I assumed it would detect changes in all cases. I guess it makes sense that it cannot do this in a web app scenario, where the entity being updated is untracked since it came in through a controller, and not from the DB context.

@ajcvickers
Copy link
Member

@mooseburger We have an issue on the backlog for making it easier to do this out-of-the-box with disconnected entities: #5536.

@mooseburger
Copy link
Author

Thanks, that does seem like it would help in this situation, were it implemented.

@ajcvickers ajcvickers added the closed-no-further-action The issue is closed and no further action is planned. label May 5, 2020
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
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

2 participants