Entity Framework and caching - Changes are tracking back to cache - model-view-controller

I have some data being pulled in from an Entity model. This contains attributes of items, let's say car parts with max-speed, weight and size. Since there are a lot of parts and the base attributes never change, I've cached all the records.
Depending on the car these parts are used in, these attributes might now be changed, so I setup a new car, copy the values from the cached item "Engine" to the new car object and then add "TurboCharger", which boosts max speed, weight and size of the Engine.
The problem I'm running into is that it seems that the Entity model is still tracking the context back to the cached data. So when weight is increased by the local method, it increases it for all users. I tried adding "MergeOption.NoTracking" to my context as this is supposed to remove all entity tracking, but it still seems to be tracking back. If I turn off the cache, it works fine as it pulls fresh values from the database each time.
If I want to copy a record from my entity model, is there a way I can say "Copy the object but treat it as a standard object with no history of coming from entity" so that once my car has the attributes from an item, it is just a flattened object?
Cheers!

Im not too sure about MergeOption.NoTracking on the whole context and exactly what that does but what you can do as an alternative is to add .AsNoTracking() into your query from the database. This will definitely return a detached object.
Take a look here for some details on AsNoTracking usage : http://blog.staticvoid.co.nz/2012/04/entity-framework-and-asnotracking.html.
The other thing is to make sure you enumerate your collection before you insert to the cache to ensure that you arent acting within the queriable, ie use .ToArray().
The other option is to manually detach the object from the context (using Detach(T entity)).

Related

In VS2013 is there an easy way to update attributes in your model?

I'm using VS2013 in a MVC 5 app. Created EF6 model using the database first approach which yielded the model as expected. Subsequently I will make changes in the database objects (tables, views, stored procs). When I go into the model to update it, the visible model will get updated. Looking at the Model Browser, I have to manually clean up the artifacts that no longer exist. Am I missing something in my procedure?
When you right click and update the model from the database, it will typically add new pieces automatically, but in my experience it doesn't automatically remove pieces that are no longer there, so you'll need to watch for those and delete them manually.
On the plus side, if you had any special customizations around a field (e.g. enum types), and the field gets renamed, this gives you a chance to compare the two configurations and make sure they line up before you delete the old field from your model.

Invalidating cache techniques when storing rich objects

There are times when you store entire object graphs into cache, or objects with collections that make cache invalidation a little tricky.
What techniques are there to know when to invalid a cache?
For simple objects you can invalidate whenever you e.g. update/save the object, you could simply make an extra call and refresh the cache.
When you have a rich object like, for example:
User
Locations
Sales
History
Now this user object will become 'dirty' whenever the user properties, or Location/Sales/History collection data is mutated.
I think one simple method would be to updated the 'modified_date' property of the user object, and maybe keep the modified_date as part of the cache key, and make a call to get the user row and then compare then pull the object graph from the cache based on the modified_date in the key:
user_cache_key + user.id + user.modified_date
The only problem with this approach is you have to make sure you update the 'modified_date' whenever any of the objects dependancies are updated.
Are there any other possible solutions to this problem?

How does one validate a partial record when using EF/Data Annotations?

I am updating a record over multiple forms/pages like a wizard. I need to save after each form to the database. However this is only a partial record. The EF POCO model has all data annotations for all the properties(Fields), so I suspect when I save this partial record I will get an error.
So I am unsure of the simplest solution to this.
Some options I have thought of:
a) Create a View Model for each form. Data Annotations on View model instead of EF Domain Model.
b) Save specific properties, rather than SaveAll, in controller for view thereby not triggering validation for non relevant properties.
c) Some other solution...??
Many thanks in Advance,
Option 1. Validation probably (especially in your case) belongs on the view model anyway. If it is technically valid (DB constraint wise) to have a partially populated record, then this is further evidence that the validation belongs on the view.
Additionally, by abstracting the validation to your view, you're allowing other consuming applications to have their own validation logic.
Additional thoughts:
I will say, though, just as a side note that it's a little awkward saving your data partially like you're doing, and unless you have a really good reason (which I originally assumed you did), you may consider holding onto that data elsewhere (session) and persisting it together at the end of the wizard.
This will allow better, more appropriate DB constraints for better data integrity. For example, if a whole record shouldn't allow a null name, then allowing nulls for the sake of breaking your commits up for the wizard may cause more long term headaches.

how can i update an object/entity that is not completely filled out?

I have an entity with several fields, but on one view i want to only edit one of the fields. for example... I have a user entity, user has, id, name, address, username, pwd, and so on. on one of the views i want to be able to change the pwd(and only the pwd). so the view only knows of the id and sends the pwd. I want to update my entity without loading the rest of the fields(there are many many more) and changing the one pwd field and then saving them ALL back to the database. has anyone tried this. or know where i can look. all help is greatly appreciated.
Thx in advance.
PS
i should have given more detail. im using hibernate, roo is creating my entities. I agree that each view should have its own entity, problem is, im only building controllers, everything was done before. we were finders from the service layer, but we wanted to use some other finders, they seemed to not be accessible through the service layer, the decision was made to blow away the service layer and just interact with the entities directly (through the finders), the UserService.update(user) is no longer an option. i have recently found a User.persist() and a User.merge(), does the merge update all the fields on the object or only the ones that are not null, or if i want one to now be null how would it know the difference?
Which technologies except Spring are you using?
First of all have separate DTOs for every view, stripped only to what's needed. One DTO for id+password, another for address data, etc. Remember that DTOs can inherit from each other, so you can avoid duplication. And never pass business/ORM entities directly to view. It is too risky, leaks in some frameworks might allow users to modify fields which you haven't intended.
After the DTO comes back from the view (most web frameworks work like this) simply load the whole entity and fill only the fields that are present in the DTO.
But it seems like it's the persistence that is troubling you. Assuming you are using Hibernate, you can take advantage of dynamic-update setting:
dynamic-update (optional - defaults to false): specifies that UPDATE SQL should be generated at runtime and can contain only those columns whose values have changed.
In this case you are still loading the whole entity into memory, but Hibernate will generate as small UPDATE as possible, including only modified (dirty) fields.
Another approach is to have separate entities for each use-case/view. So you'll have an entity with only id and password, entity with only address data, etc. All of them are mapped to the same table, but to different subset of columns. This easily becomes a mess and should be treated as a last resort.
See the hibernate reference here
For persist()
persist() makes a transient instance persistent. However, it does not guarantee that the
identifier value will be assigned to the persistent instance immediately, the assignment
might happen at flush time. persist() also guarantees that it will not execute an INSERT
statement if it is called outside of transaction boundaries. This is useful in long-running
conversations with an extended Session/persistence context.
For merge
if there is a persistent instance with the same identifier currently associated with the session, copy the state of the given object onto the persistent instance
if there is no persistent instance currently associated with the session, try to load it from the database, or create a new persistent instance
the persistent instance is returned
the given instance does not become associated with the session, it remains detached
persist() and merge() has nothing to do with the fact that the columns are modified or not .Use dynamic-update as #Tomasz Nurkiewicz has suggested for saving only the modified columns .Use dynamic-insert for inserting not null columns .
Some JPA providers such as EclipseLink support fetch groups. So you can load a partial instance and update it.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/AttributeGroup

Retrieving additional data from already loaded Magento models

There are some occasions where I'm handed a model containing only some of the data I require, for example a catalog/product instances that doesn't contain certain attributes I may need to use, such as size, widget number, or waist measurement.
To alleviate this, my current options are:
Create a new block, and load the required attributes manually using addAttributeToSelect($name).
Loading the entire model in the template using the ID from the current, inadequately populated, model with, for example, Mage::getModel('catalog/product')->getId($product->getId()).
To my question: is there a way I can pick additional attributes that I'd like to load in my model collection after ->load() has been called? Also, is there a method to do this on individual models?
The right and most safe approach (but not the best - see below) is described in question - it is to load product once again.
There are no already developed methods to add more attributes, after the product is loaded, for several reasons:
1) During Model lifetime a lot its values are calculated and cached inside the Model. Thereby adding more attributes (e.g. price) will change the Model's state, but won't affect results of several methods, that are designed to return these attributes values (e.g. getPrice()), but internally do some additional preprocessing and depend on previously calculated data.
2) The Model's state will be inconsistent, as some methods will return cached and currently non-valid values, calculated on previous empty attribute, while some other methods will return non-cached values. So usage of such Model will be unsafe and its properties will be unpredictable.
3) Complexity of code to support such reloading is quite big.
Solutions
1) The first good solution (although is the heaviest one) is to load product once again, every time your block/model/helper needs extended set of attributes in it.
2) Better solution - is to load new collection with all products having all additional attributes, whenever you see, that these attributes will be required and original collection doesn't have them.
3) The best solution - is to load original product collection with all required attributes. Sometimes collections really load products with subset of possible attributes - mainly it is a legacy code for EAV optimization (now flat tables are turned 'on' by default and this optimization is not needed) or possibly when collection is loaded by search engine (e.g. Solr in Magento EE) which, by default, doesn't store all the attributes in its records.
3.1) You can add required attributes to the original collection at the place, where it is instantiated - via mentioned in question addAttributeToSelect($attributeNames) method
3.2) You can add your attributes to the list of attributes, automatically populated in a collection. Attributes lists differ from module to module, and they are stored in different places. Some are in config, others - in database. Concrete place (config or db table), where to add attributes for auto-population, depends on your concrete case.
4) Sometimes, when you need only attribute values, it maybe much easier and faster to write Resource Model, that will directly load them from DB by productIds and current storeId scope. Then you can take risk an set them as properties to Products in a collection or safely set them to Products as myAdditionalAttribuesValuesArray property or use as independent array, mapped to product ids.

Resources