breezejs: orderBy not kept when merging collection to an existing Entity in cache - breeze

In the cache, I've got an Entity of type 'Mandate'.
Then I run the following code to fetch a collection of MandateHistory entities, which is then merged by breeze to the corresponding property of the Mandate entity :
function getMandatHistory(mandatId) {
var query = breeze.EntityQuery.from("MandatesHistory")
.where("Mandate.Id", "==", mandatId).orderBy("Id")
.expand("Mandate").skip(offset).take(pageSize).inlineCount(true);
return manager.executeQuery(query.using(service));
}
Note the orderBy clause is respected and the results are properly sorted by Id.
However the items in the collection property of the Mandate entity is NOT sorted. Do I have to do something special here ?

Sorting of the values returnd by collection navigation properties is NOT something that Breeze does. It will sort the results of a query, but if you want to sort, ( and keep sorted), one of the collection properties of an entity you will need to manage that yourself.
I think your best two options are either.
1) Sort before display. i.e. call a sort method on any collection right before you display it. Depending on what MVVM framework you are using, there is often a 'binding' that does exactly this.
2) Subscribe to the Breeze arrayChanged event on the array returned by your navigation property and call sort on the array anytime you see the change event. Note this can get expensive if you subscribe to a lot properties on a lot of entities.

Related

EF Add filter to navigation property DbSet

I want to add .Where(e => e.PartitionId = x) to all entities in Linq to Entity expression.
User could send complex query which translates into multiple navigation property, for example
Order and its customers and customer's address.
I tried capturing DbSet access but it appears to only happen for Order entity and does not happen for any of navigation property.
I can't hard code query in my code because user could be asking for Order and get its navigation property or start from any of my 20 entities.
I found EntityFramework.DynamicFilter and it is working well so far

BreezeJS mixing cache and server data unexpectedly

I'm having a weird (or at least unexpected) problem with Breeze. I have an EF back-end view model to which I send some parameters and it returns some data. I use the withParameters option to do this. The back-end does a lot of Includes and projection and returns the data I want to display in a set of custom view model entities (i.e., not database entities). One of the parameters is a list of keys for which I want to display data.
The keys identify which children of the parent entities I want to retrieve, though I am retrieving a list of parents (e.g. keys [1,2] mean it should get all Parent entities with a Children list property that themselves have a ToyId property that has a value in keys and those Child entites). In other words, the structure is like Parent.Child[] and Child.ToyId and I want to get parents with children that have certain toys and those children themselves (but not other children). Both parent and child sets are large so I do this in SQL via EF (which was an adventure in itself).
Anyway, the problem happens after I select two keys and get the data and then de-select one of the keys. The first query, getting the data for two keys, works as expected. On the second executeQuery's callback, I get the same data as the previous query, meaning it's as if I never de-selected the key. I've verified that Breeze hits the back-end with the correct keys parameter value and the back-end returns just the data I want, but it seems that Breeze is ignoring the data from the back-end or performing a union on the result set from the back-end and its cached entities (for both keys) and sending that union as results into the callback instead of just what the server returned. Is this expected behavior? Unfortunately everything is written this way. We (working on this, our first project using Breeze) all assumed it would only return what the server sent when not using executeQueryLocally, so it will be a big deal to refactor. Sigh.
I tried some where predicates which didn't work and don't see how projecting on the Breeze side would help either. I thought maybe it saw the query as identical so it returned cached data as a shortcut, so I added a where('Parent.Children', 'any', 'ToyId', 'in', keys), but that didn't work, it still brings in the de-selected results.
The only way I've found to get around this is via queryManager.clear() before I make any of the queries, and I suspect doing a noTracking query might work also (albeit without actual entity objects). I thought about converting the keys parameter into a where filter and sourcing it from there instead of the keys parameter, in case that would tell Breeze to only show the back-end data.
Is there a "correct" way of getting back only the data the server sends in the callback?
("The callback" meaning the function passed into executeQuery.then(...))
As you've noticed, Breeze merges the query results into the cache before calling your callback method. This means that, in the callback, a parent entity will have all of its children that exist in the cache.
The array of entities returned by the query is available in the retrievedEntities property of the saveResult object returned in the callback. You can use this to determine which children were returned from the query.
entityManager.executeQuery(query).then(function(data) {
var parents = data.results;
var ret = data.retrievedEntities;
//... filter ret to get the children
//... update viewmodel with children
});

Breeze: how to prevent merge to happen

Having an entity in cache, that entity has related entities in the form of a top 20.
Now a user action can update the top 20 on the server, and I thus would like to redownload the entire entity. Server sends the correct data with top 20, but in Breeze, I end up with a top 40... And I can't figure out how to avoid this behavior.
Thanks for the tip
Update: I do not use odata webapi and iqueryable, as it offers too much power to clients for my app. So I don't want to use EntityQuery.fromEntityKey, which seems to do what I want. I'd prefer to keep using a "normal" query, to which I add a parameter.
Update 2: To add more clarity as to why I want to prevent merge, when I recompute the top 20, I delete all related entries in the db and recreate them, so they have new Id's. So I am now considering an update, which might actually solve my issue BUT I would still like to know if merge can be prevented.
The Breeze EntityManager caches entities by primary key. So presumably your 2nd query is returning a completely new set of entities with each query. If this is the case, and you really only want the "latest" 20, the simplest fix would be to simply empty the EntityManager cache for this entity type before each query. Something like:
var entities = myEntityManager.getEntities(myEntityType);
entities.forEach(function(e) {
myEntityManager.detachEntity(e);
// or
// e.entityAspect.setDetached();
});
I am not sure what is exactly your qustion, but if you want to have different results on entity queries you may do it by creating 2 different controllers with different action names, or just with different parameters - overloaded methods. Then in your datacontext you can have 2 different queries.
You use .withParameters() propriety on the query to call the controller method with parameters.
Then in the controller method you can query and filter with LINQ, in any way you want. This way you can have different results based on the query/controller you chose to call.
Documentation: http://www.breezejs.com/documentation/querying-depth

What's the correct way to handle new breeze entities that might be thrown away?

I'm sure I've created my own pain here, but I'm struggling to understand the correct sequence of events to manage creating new entities in my scenario.
In my model I have two objects, ObjectA and ObjectB that both inherit from BaseObject, obviously each with their own additional properties.
In my view, as most of the information is the same, I want the user to be able to just select an option as to which one to create. So they fill out SharedProperty1 and SharedProperty2 (which is a collection navigation property), select an option as to if they want an A or B object, and then fill in a final page which has the last object specific properties.
As I didn't know which entity to create until the user had selected this option, I built a an object in the viewmodel to handle this temporary data. As part of that while they are filling out SharedProperty2 (the collection), as they add new ChildObjects, I create them with entityManager.createEntity('ChildObject'). Then when they reach the end, I create either ObjectA or ObjectB entity and add the child entitites (and other properties) and then try and save.
The problem is it never saves correctly, but I get different results depending on which approach I take. So because the user could just abort the new object process, I was creating the ChildObjects with EntityState.Detached because I thought that would be easier if they got thrown away. I realised though that all the entities created in this way get the id key 0. So then I fixed the keys while I was adding the ChildEntites to the parent (either ObjectA or ObjectB), by assigning them decreasing negative numbers (ie: -1, -2, etc). This resulted in some crazy server-side behaviour with only some entities being saved to the db and complaints of conflicting foreign keys.
This also had a bad smell that I hadn't understood this correctly, and I'd made a mess of it. So now I tried just creating the entities normally (ie: without the Detached flag), and they all get their own unique keys (again breeze appears to follow -1, -2, etc), but now when I try to copy them from my temporary viewmodel collection to the parent object collection, I get the error that an entity with this key is already attached. So now I can't even build up the correct model to save.
I still think I've not understood quite correctly how to handle this, so some pointers would be deeply appreciated.
To head off what I suspect will be a question, why I didn't use RejectChanges to handle the entities being thrown away. Basically a user can add a ChildObject (object gets created by breeze entityManager, added to viewmodel collection, bound to UI), and then decide to just remove it again (currently just gets removed from viewmodel collection) before they save their data. If I used reject changes I would throw away other important entites. I think I'm now going to be a good boy and use the proper detach method if someone removes the ChildObject in the view.
If I understand your question correctly, you are trying to create some properties and then add them to a parent objects collection when saving. Correct me if I am wrong, but Breeze not only supports this, but does so very efficiently. Having come from .NET and C# it was very difficult for me to grasp how easy this can be, but this is what I would do if I were you -
var childA = ko.observable();
var childB = ko.observable();
childA(entityManager.createEntity('ChildObject')); // populate your children
childB(entityManager.createEntity('ChildObject')); // populate your children
Then you can edit them in your view, and when you are ready to save simply add them to the collection.
var save = function() {
isSaving(true);
var parent = ko.observable();
return entityManager.getParent(parent, parentId)
.then(setParents)
.fail(catchError);
function setParents() {
childA().parent(parent());
childB().parent(parent());
entityManager.saveChanges()
.then(complete)
.fail(catchError);
function complete() {
isSaving(false);
return Q.resolve(); // Don't know if you have any unresolved conflicts
}
}
};
Basically in this manner we are -
A : Creating the entities
B : Editing them without performing any changes
C : When we call save we are setting their parent navigation property. In my prior ways (be it right or wrong) I would have simply set ParentId(parentId) and let EF figure out how to navigate but (pardon the pun) this is a breeze with Breeze. We could also just as easily pass in a parent observable and not have to go get it from the manager, it just depends on whether we have it already or not.
Another way you could do this if you want to manage the entities separately is to save a single entity at a time with entityManager.saveChanges([childA]) as they are ready. Just pass in an array with a single entity that you want to save. This may be useful if you are working on multiple entities but they aren't all ready for saving and you need to navigate around your app. Unless you call cancelChanges() Breeze will just keep the entity in cache until you are ready to use it again. In this manner, just make a call for entities in the isAdded() state and you can pull 'em back in and edit again.

Performance implications : Entity table reference vs List of that table reference

I am using entity framework and developing an architecture for application with remote data access. Coming back to point, i query the database for one record (say on the basis of itemcode). Now the resultset i will get whether i should return it as List or collection or simple as an object of entity. I am using entity object but my boss is saying i should use List. He thought , returning result as an entity with return whole table structure also. Quick suggestion would be appreciated.
List<Employee> lstemployee = GetRecordByCode(itemCode)
or
Employee emp = GetRecordByCode(itemCode)
What's the difference? If itemCode is a unique key you will either get one Employee object or a list containing the same one Employee object. You will never return the whole table. That will only happen if within GetRecordByCode you do something like context.Employees.ToList() without any Where filter before the ToList().
If itemCode is not unique you even have to use a list.

Resources