Search code examples
breeze

breeze EntityManager: how to attach plain javascript object


I have custom OData action that is called from my client. The results from this action are a list of JSON objects which need to be merged back into the Breeze cache as entities. How do I convert a JSON object into a Breeze entity and merge that entity back into the entityManager's cache? Some code:

   $http.post('/odata/MyEntityType/MyCustomAction/', {
                    'someData': JSON.stringify(element1),
                    'SomeOtherData': JSON.stringify(element2)
                })
                .success(function (results) {
                    //results.value is an array of *MyEntityType* JSON objects.   `//Is there a way to convert these to breeze entities?`

                    });

Some things I have tried:

manager.importEntities("MyEntityType", theJsonForAnEntity); //just stabbing in the dark here

manager.createEntity("MyEntityType", theJsonForAnEntity); //error: A MergeStrategy of 'Disallowed' does not allow you to attach an entity when an entity with the same key is already attached"


Solution

  • createEntity won't work

    Sorry, Jeremy, but that isn't going to work. Here's a test that shows why:

    // Failing test
    test("merge customer date into existing cached entity using `createEntity`", function () {
        var em = newEm();
    
        // Create an unchanged entity in cache as if it had been queried
        em.createEntity('Customer', {
            CustomerID: dummyCustID,
            CompanyName: 'Foo Co',
            ContactName: 'Ima Kiddin'
        }, UNCHGD);  // creates the entity in the Unchanged state
    
        // Try to merge some changes into that entity using createEntity.
        var changes = {
            CustomerID: dummyCustID,
            CompanyName: 'Bar Co',
        }
        var cust = em.createEntity('Customer', changes, 
                       UNCHGD, breeze.MergeStrategy.OverwriteChanges);
    
        ok(cust.entityAspect.entityState.isUnchanged(), "cust should be 'Unchanged'");
    
        // using Knockout; it's simpler if using Angular
        equal(cust.CompanyName(), 'Bar Co', "Company name should be updated by merge'");
        equal(cust.ContactName(), 'Ima Kiddin', "Contact name should be unchanged after merge'");
    });
    

    The third assert fails because the createEntity method overwrites every property, not just the one data value of interest (CompanyName in this case). That means that ContactName is null.

    importEntities won't work either

    For the same reason. When you import an entity, you import the entire entity, not just some portion of it. So that too would wipe out the ContactName in this example.

    Manual merge

    I think if you want to blend the results with the entity in cache, you'll have to do that by hand. You'll have to iterate over the results and update the cached equivalents.

    Imagine that the changes variable above is result of your POST. The following test does pass:

    // Passing test
    test("merge customer date into existing cached entity", function () {
        var em = newEm();
    
        // Create an unchanged entity in cache as if it had been queried
        em.createEntity('Customer', {
            CustomerID: dummyCustID,
            CompanyName: 'Foo Co',
            ContactName: 'Ima Kiddin'
        }, UNCHGD);  // creates the entity in the Unchanged state
    
        // Merge some changes into that entity
        // Imagine that `changes` came from your server as a result of your POST
        var changes = {
            CustomerID: dummyCustID,
            CompanyName: 'Bar Co',
        }
    
        // First find the customer in cache.
        // Here I'm assuming it will always be there; you should be careful
        var cust = em.getEntityByKey('Customer', changes.CustomerID);
    
        // using Knockout; it's a little simpler in Angular
        for (var p in changes) { cust[p](changes[p]); }
    
        cust.entityAspect.setUnchanged(); // cuz the previous updates changed the state to "Modified"
    
        ok(cust.entityAspect.entityState.isUnchanged(), "cust should be 'Unchanged'");
        equal(cust.CompanyName(), 'Bar Co', "Company name should be updated by merge'");
        equal(cust.ContactName(), 'Ima Kiddin', "Contact name should be unchanged after merge'");
    });
    

    Feature Request

    I can imagine a future in which Breeze could automate this for you with all of the appropriate error checks. If you think such a "JSON entity merge" feature would be a valuable enhancement to Breeze, please add that to User Voice. I would be quick to agree but we can't add features unless people want them.