I need a way to track modified properties and audit them.
I am hooking into SaveChanges where I get the modified properties
//Get only Modified Customer entries
var modifiedCustomerOses = context.ObjectStateManager
.GetObjectStateEntries<Customer>(EntityState.Modified)
.ToList();
What I have noticed and I am using EF4 with codeGeneration that it reports when a property is not really modified as modified.
If a property EG "CustomerName" is set to "John" and when I do an update I dont change the name but I do
EntityCustomer.Name=customerDto.Name and the name are exactly the same it still reports as changed.
I have looked at the generated code and cannot see if EF property does a check like
if(name==value)//propertyNotchanged dont raiseevent.
Any suggestions? Do you know how EF4 determines if a property has really changed?
thanks
The tracking is performed on entity level, not on property level.
The more appropriate way to trace if the property was changed is to use the OnPropertyChanged partial method.
Just create a custom code that will hold the changed properties.
Related
Im trying to find out which attributes of an entity have been changed.
As far I have seen, there is a PersistenceSession with a method to check an object if an attribute isDirty. But its always true because it never registers the old object.
So if I take the demo from the QuickGuide and override the update method in the CoffeeBeanRepository:
/**
* #param \Acme\Demo\Domain\Model\CoffeeBean $coffeeBean
*/
public function update($coffeeBean) {
\TYPO3\Flow\var_dump($this->persistenceSession->isDirty($coffeeBean, 'name'), "name changed before");
parent::update($coffeeBean);
\TYPO3\Flow\var_dump($this->persistenceSession->isDirty($coffeeBean, 'name'), "name changed after");
}
... its always TRUE (both), despite I didn't change anything.
Anyone an idea/reference how this can be accomplished?
I am using it for a REST API where a user can't update several fields and on editing of some fields additional actions have to be executed.
The persistenceSession is part of the generic persistence backend of Flow and is neither maintained, nor really used unless you explicitly deactivate doctrine. Hence persistenceSession will not help you, because all entities are considered new for the persistenceSession as you noticed.
With doctrine you need to get the entity changeset from the "UnitOfWork", which you can get from an injected \Doctrine\Common\Persistence\ObjectManager. See also Is there a built-in way to get all of the changed/updated fields in a Doctrine 2 entity
However, this is a suboptimal solution and a hacky work-around at best. If you need to track changes to your entity, it should be an explicit part of your domain model. For example make your setters record a changed properties list, when the given value is different from the current.
When done, you could even optimize doctrines change tracking on the way with that: http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html#notify
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.
i would like to create new entities which use the default values defined in the model.
i've checked the retrieved metadata, and the default values are there:
{"name":"LastName","type":"Edm.String","maxLength":"50","unicode":"true","fixedLength":"false","defaultValue":"admin:
Nachname"},
however they are not taken into consideration when creating a new entity.
This is a bug in Breeze that should be fixed in the next release, out in about week. When this fix gets in then breeze will honor any defaultValues it finds in the EntityFramework data model.
One problem though is while it is easy to get 'defaultValues' into a Model First Entity Framework model via the properties editor, it's actually difficult to get it into a Code First EF model, unless you use fluent configuration. Unfortunately, EF ignores the [DefaultValue] attribute when constructing Code First model metadata.
One workaround that you can use now is to poke the 'defaultValue' directly onto any dataProperty. Something like:
var customerType = myEntityManager.metadataStore.getEntityType("Customer");
var fooProperty = customerType.getProperty("foo");
fooProperty.defaultValue = 123;
In my database User table I have DataTime field called DateDeleted - which is null while user exists and is set to the proper value when user "is deleted".
I wonder if there is a way to introduce IsDeleted property for User entity so that
http://odata/service.svc/Users(1)/IsDeleted
will return true or false depending on whether DateDeleted is set or not
My research in google hasn't got any results and I am almost sure it is not possible to implement through odata. Am I right?
With the built in providers this is not possible on the WCF DS side of things. You might be able to somehow do this on the EF side (expose it as a property of the EF entity), but I'm not sure if that's possible.
On the WCF DS side, you would have to implement a custom provider in order to do this. Which may be quite a lot of work unfortunately. If you're interested see this for starters: http://blogs.msdn.com/b/alexj/archive/2010/01/07/data-service-providers-getting-started.aspx.
What Shawn refers to above is a method on the custom provider interface.
You can specify the value you want by implementing the method DataServiceQueryProvider.GetPropertyValue.
Please find the reference here:
http://msdn.microsoft.com/en-us/library/system.data.services.providers.idataservicequeryprovider.getpropertyvalue.aspx
The method takes two parameters, the entity object (a User instance) and the resource property (in this case "IsDeleted"). You can try to get the property value of "DataDeleted" from the entity object, and return the value of "IsDeleted" as you want.
I am implementing OnSaveChanges() when saving an entity.
Apart from finding out all the properties of the entity that have changed how do I find out all the properties of a collection within the entity that have changed?
EG
Customer has a property
public List<Address>AddressList {get;set;}
Now if one of those addresses changes how do I detect it?
I am using the following to detect all the ObjectStateEntry modified
IEnumerable<ObjectStateEntry> changes =
stateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted);
now as a said apart from the changes to the entity I need to find all the changes to the collections the entity might have.
How do you do it?
You will need to call ObjectContext.DetectChanges() prior to calling SaveChanges(). If you don't do this, the items in the collections will not be included in GetObjectStateEntries at the time of your SavingChanges method being called.