I am able to create an entity object, set some default values and add it to the manager. Now I want to track the changes to it using manager.hasChanges(). For some reason, this always returns true. Should I be checking something else too when tracking newly created entities that are not in the database?
EntityManager treats an entity with EntityState.Added as a 'changed' entity. This is why HasChanges will always return true.
In this case, you should listen to EntityManager.entityChanged event to track changes.
See http://www.breezejs.com/sites/all/apidocs/classes/EntityManager.html#event_entityChanged
As soon as you 'Add' it to the EntityManager, by definition, it has changes because it is in an 'Added' state. To breeze 'hasChanges' means that it needs to be saved because it is 'different' from what was provided by your persistence service ( in this case the entity hasn't yet been 'saved').
What you can do is 'Attach' your entity to the EntityManager in an 'Unchanged' state.
myEntityManager.attachEntity(newEntity, breeze.EntityState.Unchanged);
In this case, any changes you make will work the way you want, BUT ...
Breeze will now consider your newly attached entity to already have been persisted and if you try to save it, then the save will fail because breeze will try to 'modify' the persisted entity instead of creating a new one.
If you really want to accomplish your request you will need to use 'attach' but also keep track of these entities and mark them 'added' before you attempt to save them.
Related
I have a scenario where I know the primary key of an entity (retrieved from an unrelated source), and I want to update just 1 property (db column). I have NOT already retrieved the entity from the database. If possible I would like to not have to make this extra round trip.
I create the entity using manager.createEntity.
I update one of the properties.
Then set the entityAspect to setModified();
When saving changes, all the properties that were not updated are set to their default values, and the generated SQL UPDATE statement attempts to update all mapped columns.
Is there a way to tell breeze to only generate SQL for specific properties/columns?
thanks
As you discovered, the properties of the originalValuesMap guide the Breeze server's ContextProvider as it prepares the save request. This is documented in the ContextProvider topic.
In your example, you call setModified after you've changed the property. All that does is change the EntityState; it doesn't create an entry in the client entity's entityAspect.originalValuesMap ... therefore the originalValuesMap sent to the server is empty.
I'm a little surprised that the EFContextProvider.SaveChanges prepared an EF update of the entire entity. I would have guessed that it simply ignored the entity all together. I'm making a mental note to investigate that myself. Not saying the behavior is "right" or "wrong".
You do not have to manipulate the originalValuesMap to achieve your goal. Just change the sequence. Try this:
var foo = manager.createEntity('Foo', {
id = targetId
}, breeze.EntityState.Unchanged); // create as if freshly queried
foo.bar = 'new value'; // also sets 'originalValues' and changes the EntityState
manager.saveChanges(); // etc.
Let us know if that does the trick.
Im talking about asp.net mvc
so basically an instance of the dbcontext gets initialized, puts the data in the view then it gets disposed of.
how does it track changes made to the entity if the "entry" which contains the original and present value get ...well disposed of.
Well, it doesn't.
Let's say you fetch an entity from the database for an edit view. Then the edit view is generated from the entity. Now the context is disposed, as it is not needed anymore. We have all the data needed to create view. Context doesn't track any changes you do in the view and when you think about it, how could it anyway?
Now you post the edit view. Context has no idea that the model has been changed. On the edit action method you mark the posted entity as dirty with db.Entry(entity).State = EntityState.Modified that doesn't do anything yet really, but when you call db.SaveChanges all the dirty entities are updated, added or deleted. After this the context is disposed again.
The point is EF doesn't track the changes for you, it's you who decides which entities are being updated. It updates the entity yes, but it doesn't know what has been changed since the last update (atleast I think so, why would it need to track the changes?).
I am keeping local entities in breeze cache, how can i delete them from the cache with out going to the server?
in the documentation it states
Deleting an entity
You delete an entity by changing its EntityState to “Deleted” like this:
1
someEntity.entityAspect.setDeleted(); // mark for deletion
setDeleted does not destroy the object locally nor does it remove the entity from the database. The entity simply remains in cache in its new “Deleted” state … as changed and added entities do. A successful save does delete the entity from the database and remove it from cache.
You can do this by detaching the entity from entity manager by calling manager's detachEntity method :
manager.detachEntity(entity);
The detached entity will eventually be garbage collected.
Refer to Breeze-Inside Entity
You can do
entity.setDeleted();
and then call
saveChanges method.
if you want to save it in DB.
if not want to go to server
manager.detachEntity(nameofYourEntity);
I am trying to add an entity to the DB. Once I have added it, I want to detach it, so I can manipulate the object safely without making any changes to the DB. After calling context.SaveChanges() I do the following to detach the entity:
// save
context.Stories.Add(story);
// attach tags. They already exists in the database
foreach(var tag in story.Tags)
context.Entry(tag).State = System.Data.EntityState.Unchanged;
context.SaveChanges();
context.Entry(story).State = System.Data.EntityState.Detached;
However, changing the entity state to DETACHED will remove all related entities associated with the my entity. Is there a way to stop this ?
If I don't detach the entity, all my changes are sent to the DB next time I call context.SaveChanges()
Thanks!!
There is no way. It is limitation of EF. Your options are:
Not using the same context for another save (single context instance = single save)
Retrieve the entity from database again using another context instance which will not be used for saving
Create deep clone of your entity and use the clonned one (deep clone is done by serialization and immediate deserialization = your entity graph must be serializable)
I think there are two ways to approach this problem:
Purist: retrieving entities from a DbContext and modifying them without saving is a misuse of the tools and the architecture. Use a DTO instead.
Pragmatic: you can use AsNoTracking() to retrieve an entity graph that will not be tracked by the context for changes.
I'm using Entity Framework with an AS.NET MVC application. I need to allow the user to create new records and modify existing ones. I am able to fetch existing records no problem, but when I pass back in the edited entity and try to save it it creates a new one and saves it and leaves the original unmodified.
I am getting the object from EF using the primary key (e.g. ID number for an employee record). I successfully retrieve it, and set the MergeOption like so:
Context.Sector.MergeOption = MergeOption.NoTracking;
I am able to trace that the object has the correct data (using the key of the original record) all the way down to the point where I call:
Context.SaveChanges();
However, after that, the new record is created instead of modifying the existing one.
Is there something obvious I am missing here? I would have thought that retrieving the object and changing some of its values (not the ID) and saving it would just work, but obviously not.
Thanks,
Chris
"NoTracking means that the ObjectStateManager is bypassed and therefore every access to the Entity Objects results in a fetch from the database and the creation of new objects."
-- http://blog.dynatrace.com/2009/03/11/adonet-entity-framework-unexpected-behaviour-with-mergeoptions/
I don't think NoTracking is what you want.
From your comment: "distributed across various tiers and some proprietary libraries"
Are you new()ing up a ObjectContext, closing it or losing the reference to it, and then trying to save your object to a new() or different ObjectContext?
If so your losing all of your change tracking information. If this is the case then you want to call the Attach() method to reattach the entity to the context, ApplyPropertyChanges() and then finally SaveChanges().
Julie Lerman has a pretty good blog post that outlines all the different change tracking options and techniques that are available. You should also check out this MSDN article on the same subject.