I am working with EF6 and have 2 objects which are linked together (A has B). When i query A (byId), a proxy object for B is retrieved. When I access properties of B, the proxy object is 'expanded' and retrieved entirely from the database.
However the only property i need to have is the Id of B (in order to serialize it from my API). Is there a way to tell EF to not load the entire object if the requested property is already in memory?
Related
We built a mechanism that on server request automatically retrieves the entities list from the DB, and maps them to ViewModels. We can't figure out how to support clearing View Models that are built from multiple DB entities when an update was made to some relevant DB entity.
This is how we've built our Cache:
We have a mapping between the key (the DB entity name) and the list of values it holds (View models).
This is how we handle entities invalidate:
On EF's Context Save method, we clear the Cache values by the saved entity's name (when it has been changed).
For most entities, all the Cache values are mapped to a single entity.
For some entities however, the Cache values depend on several other entities (which are either direct or indirect navigation properties of the entity).
For instance:
We have an EducationPlace Entity.
Its Cache key is "EducationPlace". Its values are a list of EducationPlaceViewModel.
EducationPlace entity has an Address property, and the Address entity, has a City property.
City's name is used in the EducationPlaceViewModel.
Now we want, that when the City entity is being updated, the Cache's EducationPlaceViewModel list will be cleared.
What we are looking for, is a way to update a cache entry, when an entity that the cache entry's View Model depends on is being updated.
The two solutions we've considered are:
Use reflection to find which entries should be cleared (by following the navigation properties). This will create many unnecessary dependencies, which will result in many redundant cache clears. For instance, EducationPlace has many navigation properties that are not being used by its View Model, hence should not trigger a Cache clear.
Use a custom Attribute that will decorate each relevant entity, and will hold its list of entities that its View Model depends on. This way we will easily get the entities that should be cleared when an entity is being saved at the Save method.
This way requires A LOT of maintenance. It requires for each new entity which its View Model depends on other entities for the developer to remember to use it on the new entity, and to update that entity when its View Model depends on new entities.
This is how we clear the View Models.
This method is invoked from the Context's Save method:
What this method basically does is:
It gets all the DB entities from the DAL layer
For each entity name, it:
a. Skips none-relevant entities
b. if the entity name exists as a Cache key - Clear its data
Scenario:
I use breeze for querying in our SPA and raw http methods for POST PUT DELETE methods.
A POST method on a resource returns the created resource including it's created childobjects.
I want to attach this created resource to the beeze entity manager.
I've tried adding the entity using
manager.createEntity('Driver', data, breeze.EntityState.Unchanged);
where the data object contains the driver resource and an array of related child entities.
But get an exception: "Collection navigation properties may NOT be set."
Do I have to create the local entity by hand and attach the child entities or does breeze support this scenario?
The reason for this exception is that the 'createEntity' method creates the entity and then assigns your 'data' to it, but for any collection navigation properties the collection already exists and Breeze won't allow you to replace it. This was a deliberate choice for existing entities where other parts of the application might hold a reference to the collection, but is overkill in this case where you are the 'first' to access the collection. For now, the workaround is to update any navigation collections instead of replacing them.
So the simplest way to do this is to call the createEntity method without any collection data properties, and then push data into your collections
var driver = manager.createEntity('Driver', dataWithoutCollections, EntityState.Unchanged)
// then update collection properties by pushing into them.
trafficFines.forEach(function(trafficFine) {
driver.trafficFines.push(trafficFine); // or use push.apply
};
Note that adding to an entity's collection properties will not cause an EntityState change so this should be sufficient.
Based on this issue, I will add a feature request to suppress this exception in the case where you are calling the 'createEntity' method, since there is no danger that some other part of the application has already had access to the new entity.
In ASP.NET, we always store an object or a collection into cache, this is, when we want to use them, we can judge if the object or the collection has already exist in cache, if exist, we retrieve it from cache, if not, retrieve it from database. Does EF has the similar mechanism, after calling "context.ObjectSet.AddObject(object)" or calling method to attach an object to the context, save it to the cache, and when we want to retrieve the object, judge whether the object has already exist in cache first. Anybody can help?
You must query ObjectStateManager to find if it already contains your entity:
var entity = context.ObjectStateManager()
.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<YourEntityType>()
.FirstOrDefault(...); // uniquely identify entity you are looking for
I am designing a database for storing products and some properties belonging to them. The properties can be inherited from parent product to the child product. For example:
ProductA ---> PropertyA, PropertyB
|-ProductB ---> PropertyC
In this example, ProductB should have PropertyA and PropertyB in addition to PropertyC. In order to get all the properties of a certain product, I need to go through all the parents and accumulate all the properties in a list. However, the Property class itself is a database entity, so can I use it to define normal objects (i.e. detached from database) without having them affecting the database contents, i.e. create, modify, delete instance as normal C# objects?
Yes you can. Entity Framework 4.0 onwards supports what is known as a POCO entity (Plain Old CLR Object). They can exist entirely separately from your database concerns and when appropriate you can attach them to an instance of an Entity Framework Context for persistence to the database.
Likewise you can Detach entities from a Context having retrieved them from the database through the same Context should you choose to manipulate them within your Domain Model in such a way that you don't want them persisted again.
Depending on whether you're doing true Code First or Database First will determine the development workflow you use for creating these entities.
Context: Repository-pattern, WCF, WPF/SL
In my Repository of self-tracking Entities i need to explicitly load some related properties in order to correctly process the query. Those are not the includes requested by the client and i would like to get rid of them in order to keep network traffic resonable. My solution so far is this:
Receive Query
Load includes necessary to answer request
Execute Query
Create temporary IEnumerable
Iterate 4) and load all items again, this time with the include-path requested from the client-app only
return entities via WCF
I would like to do this:
Receive Query
Load all includes (infrastructure plus client-requested)
Execute Query
Unload "Infrastructure" includes
return entities via WCF
What is the proper way to do this?
Thanks,
Armin
How about lazy loading and proper DTO response objects ?
WCF returns custom Order or GetOrderResponse (Contracts.Order)
Load Order from EntityModel through repository (just the order)
Use automapper for mapping EntityModel.Order => Contracts.Order
Result : only the corresponding properties inside Contracts.Order are loaded:
Ex. Contracts.Order
Number
OrderDetails (=> Only this property is loaded through lazy loading because it is mapped)
If you are building a SOA or webservice, don't let the client specify load graphs. If it's necessary for the client to specify load graphs consider deploying the Model using WCF Data Services, works great.
Perhaps you could build two systems .. one SOA and one (readonly) Data Service.