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
Design meeting notes - December 4, 2014 #1248
Comments
I have a question about AttachGraph. Sometimes I have a graph and just want to attach or add the root and not worry about someone having reference data attached as a navigation property. For example if I have an address object and developer set Address.Country=entityInstanceOfSomeCountry, I want to avoid adding the country by mistake if I add the address. (There is the question of whether or not the CountryFK property has been populated.) Would be nice to have some method ala AttachRoot that would attach the root, work out FK values for scalar FK properties and leave the navigations null. I've been struggling with this in disconnected EF since v1. Thanks |
Hi Julie, I think the problem you're describing (setting entities for navigation properties to Added) won't be an issue in EF7, because Add will be non-recursive. For example, settings Address to Added will not automatically set Country to added. I had to contend with the legacy behavior in my Trackable Entities project where I set EntityState based on state metadata traveling with entities through the client round-trip, which made applying change state recursively quite tricky to say the least. :) Thumbs up from me for the the improved support for the disconnected scenario, including the proposed AttachGraph method. I like the idea of making public the graph iterator, which could be re-purposed for client-side graph traversal, and I support plug-ability with DI integration. Regarding the simplified version [void AttachGraph(object root)], the docs would need to clearly state that it's intended only for entities that use EF key generation (for ex, identity). So it wouldn't work with Customer from Northwind, where they PK is a string. I'm fine with that, however, because it's more of a "quick and dirty" version of AttachGraph. Cheers, |
Thanks. I'll go play with this stuff.
|
another point I'd like to mention is to please do what you can to provide consistent behavior. There are so many anomalies with current behavior of add/attach/etc. Sometimes there is logic to it if you really grok what's going on but in some cases, even I can't explain why results are different from one scenario to another. I think root add/attach/udpate/remove only affecting the root ... period ...should remove a bulk of the problems. It will be the proposed attachgraph method that you'll need to watch out for. Thanks |
@julielerman @tonysneed - We also have an overload of AttachGraph that takes an Action where you can set the state you want the entry to be in. Not setting the state means the entry remains effectively detached... so for the more complex scenarios you can always have logic that only attaches/adds certain entities. |
I agree with @julielerman. Although you can use the overload I prefer a more explicit and easy to use method (AttachRoot). It would be especially useful for people starting to use the API. |
I really like a version of AttachGraph that accepts an Action because it lets you set the entity state using whatever criteria you want. For example, I would set state based on some sort of metadata (tracking state), including property-level state for partial updates. I'm not so crazy about a version of AttachGraph that actually sets state to Updated or Added. First, I'm not sure how useful it would be -- it would not support partial updates, deletes, or adds with non-integer keys. Second, the name is a bit misleading. Attach should, well, attach the entity, that is, set the state to UnChanged. But I'm still not sure how useful that would be, because you would have to "replay" the updates, which is not ideal, or call Add/Remove, which already attach the entity. So my vote would be to keep this version: void AttachGraph(object root, Action<EntityEntry> callback) And drop this one: void AttachGraph(object root) Cheers, |
I agree with @tonysneed that the AttachGraph method that accepts callback will be very useful . But (IMHO) I also think it is important to create a method (AttatchRoot like @julielerman says) to facilitate basic scenarios without having to worry about writing the callbak to customize the entity state. Thanks! |
@pacoweb - How would AttachRoot differ from the DbSet.Attach which just attaches the entity that you pass to it? |
Yeah @pacoweb you may not realize that attach/add only touch the root now, not the graph. Big break from the past but probably the only way to ensure consistency. I wasn't aware of that when I opened this. So now the issue is working out if/when/how/which WRT attaching the rest of the graph (if there is one). |
@rowanmiller - @julielerman - My only concern was the name . I like apis with explicit names. I like AttachGraph is clear. AttachRoot would also be very clear. Thanks! |
There does not appear to be any discussion surrounding deletions when attaching a graph. Is this tracked anywhere? |
We are closing this issue because no further action is planned for this issue. If you still have any issues or questions, please log a new issue with any additional details that you have. |
Graph behaviors
Goals
Background
The old stack always attached the entire graph of reachable entities in the same state. That is, if you called Attach, then everything reachable would be put in the Unchanged state. When attaching a graph where some entities already existed and some were new this meant that:
Ultimately, we want to support the following strategies for determining the state of new entities:
Proposal
The main part of the proposal is to introduce a new method
void AttachGraph(object root, Action<EntityEntry> callback)
This method starts at the root entity and uses graph traversal to find other entities in the graph. For each entity the callback delegate is invoked which can set the state of the entity as appropriate. The callback delegate could also do other things such as setting original values or adding shadow state.
Notes:
An additional part of the proposal is to introduce a simple version of AttachGraph:
void AttachGraph(object root)
This method would use a callback that looks at the primary key value to determine whether an entity should be Added or Unchanged.
Notes:
We also discussed removing the single object Add/Attach/Update/Remove methods and replacing with:
EntityEntry<TEntity> Attach<TEntity>(TEntity entity, EntityState state)
This is because each of these four methods does exactly the same thing just with a different state. We decided not to do this as it was felt the existing methods would be easier to understand and preserves some level of experience from EF6. Also, this method is effectively the same as setting the state with
context.Entry(Foo).State = newState
. However we decided that given setting state can now be a significant amount of work and may be async we will make the State property read-only and add SetState and SetStateAsync methods.DbSet Queries
Background
Currently DbSets are IQueryables and using them results in a database query. However, they also have Add, Remove, etc. and so act as a way to introduce entities into the unit of work, etc. But since the query is still a database query it means that if those new entities are not returned when the set is enumerated. This is usually unintuitive to new users. For example:
On the other hand, most people seem to like this syntax for writing database queries and do find it intuitive:
So having the DbSet work as a database query is not universally bad.
Options
One option which would be perhaps the most intuitive is to make DbSet queries integrate database results with local results and return the union of both. We would like to do this, but we don't have time to do it now. Given that we can't do this now, other options are:
We decided to go with the first option and keep the current semantics. This is because:
Hopefully in the future we can implement the combined query semantics and then enable this with a flag on the context or through a new DbSet type.
Migrations and namespaces
Recent changes mean that when a new migration is added it will be placed into the same namespace as the previous namespace for that context. There was agreement that this was good, but the following tweaks were suggested:
Discussion
Please comment on this issue to provide feedback, ask questions, etc.
The text was updated successfully, but these errors were encountered: