Batch processing on the client with the updatesManager class.

Requires MVCControlToolkit.Controls.Core.x.x.x.js, MvcControlToolkit.Bindings-x.x.x, knockout.x.x.x.js, knockout.mapping.x.x.x.js, MvcControlToolkit.Utils-x.x.x.js, and MVCControlToolkit.JsQueryable-x.xx.min.js.

MvcControlToolkit.Utils-x.x.x.js must be placed AFTER knockout.x.x.x.js, since it checks if knockout.js features have been installed

The updatesManager allows the batch processing of a collection of objects. It takes care of sending the change set resultig from the updates to the server, receiving and dispatching in the right place in the UI possible server errors and  possibly receiving and dispatching to the right objects the keys of the Inserted objects generated on the server. The updatesManager can be used to communicate with both ApiControllers and with standard Action Methods.

The change set consists of three lists:

  • The list containing of all modified objects.
  • The list containing the objects created on the client(Inserted list).
  • The list of all keys of the objects that have been deleted on the client. 

As we will discuss later on, the change set of children objects contained in properties of other objects, contains also another list: the father reference list. This list is necessary to handle newly created objects that are children of newly created objects. 

We can create an instance of the updatesManager that handles a collection of objects C with:

 

mvcct.updatesManager(
        updateUrl,
        sourceViewModel,
        sourceExpression,
        keyExpression,
        destinationViewModel,
        destinationExpression,
        options
        )

 

where:

  • updateUrl, is the url where to submit the updates with an Http Post.
  • sourceViewModel, is the Client Side ViewModel that contains the collection of objects C whose updates we would like to submit to the server.
  • sourceExpression is a string expression that locates the collection C within sourceViewModel. The collection C can be contained also in an objects that is nested in a property of  sourceViewModel, so, in the general case, sourceExpression has the form property.subproperty.subproperty1....
  • keyExpression is a string expression that locates the key of each each object. This key doesn't need to be a database key but just a property that univocally identifies the object. 
  • destinationViewModel is an object where to put the change set computed by the updatesManager. It is the javascript translation of the server side ViewModel of the Action Method that will receive the updates. Several updatesManager can use the same destinationViewModel, this way several changes set can be sent to the server with a single Http Post.
  • destinationExpression is a string expresson that identify the property where to put the change set in the destinationViewModel. If needed, all objects and properties in the path specified by destinationExpression are automatically created, so we can use also {} as destinationViewModel: all needed properties will be added when adding all change sets to it.
     
    If destinationExpression and destinationViewModel are null the change set is sent to the server as it is without inserting it into a container object.
  • options, an object containing some options.

The options object can be provided also after having created the updatesManager by calling the options(o)method.

For a quick start on the  mvcct.updatesManager see the tutorial: Mvc Controls Toolkit Support to Mvc4 WebApi

If the objects of the collection C contain properties with arrays of other children objects, that is,  if C is connected to other object collections with one-to-many relations, then, for each of the related collections, we have to define a different updateManager. These updatesManagers specify where to place the change sets of the children collections into the destinationViewModel through their destinationExpressions. They must specify also the sourceViewModel and sourceExpression;  when the father updatesManager is going to submit the destinationViewModel it copies all children objects by reference  from the properties they are in into the properties identified by the sourceExpressions of their updateManagers and then it triggers the computation of all children changes sets.  

The father-children relation between two collections is declared by calling the addChildUpdateManager of the father updatesManager:

 

addChildUpdateManager({ expression: <collection>, external: <external key>, updater: <child updateManager> });

 

Where:

  • expression, is a string expression that specifies which property of the father objects contains the children entities.
  • external, is a string expression that specifies wich property of the children entities works as external key.
  • updater, is the updatesManager of the child collection.

 It is also possible to declare the updatesManager needed to handle the child collection in the within the addChildUpdateManager:

 

addChildUpdateManager({ expression: <collection>, external: <external key>}, chidlCollectionKey, childDestinationModelProperty);

 

Where:

  • childCollectionKey, is the expression that specifies the key of the child objects set.
  • childDestinationModelProperty, is the destination expression to be used by the child updates manager
  • the value returned by the addChildUpdateManager is the newly created child updates manager

An updatesManager can be declared as child of itself if each object can contain objects of the same type as children in some collection. In general circular references are allowed in the father-children graph of all updatesManagers.

For a quick start on the  mvcct.updatesManager see the tutorial: Mvc Controls Toolkit Support to Mvc4 WebApi 2: Handling Relations

Basic operation of the updateManager.

Using the updatesManager is quite easy. The basic steps to use it are(for the details on all updatesManagers methods, see the updatesManagers reference at the end of this section):

  1. Creating all needed updateManagers: one for each changes set we would like to pass to the server.
  2. Passing them all needed options, either in the constructor or with the options(o) method.
  3. Declaring possible father-children relations by calling the  addChildUpdateManager of the father updatesManager.
  4. As soon as we receive new objects on the client, prepare them by calling the prepare method of their updatesManager, either on each of them, or directly on an array of objects. Preparation must be done after objects have been deserialized, and after having added the needed ko observables and observableArrays to them, that is after having called ko.mapping.fromJS on them. In the updatesManager options we can declare a prepareCallback function that is automatically called after object preparation. The prepareCallback is usefull to add custom behaviours to each object.
  5. Each time you modify an object call the modified method of its updatesManager to declare it has changed. This can be done either while handling a save, or done button click, or by subscribing a function (ko subscription) that calls the modified method to all observables of the object that the user can change(this function subscription can be accomplished in the prepareCallback).
  6. To delete an object call the deleted method of its updatesManager. This will cause the logical delete of the object that will disappear from the User Interface and will be marked as deleted.
  7. To add a new object, as a first step create it, and add observables and observableArrays as needed. Then, if the object has no father, simply , prepare it by calling the prepare method its updatesManager and then call the inserted method of its updatesManager. If, instead, the new object must be added as a child of another object, just call the addChild method of the father updatesManager, and pass it the new object and the name of the collection where to append it. Preparation will be done automatically by the addChild method.
  8. The move method of the updates manager move one child object from one father to another. Children can be moved from father belonging to different updatesManagers. The move method must be invoked on the updatesManager of the destination father.
  9. Changes done to an object can be undone by calling the reset method of its updatesManager. This will cause modifications to be undone, deleted objects to re-appear and newly inserted objects to disappear. When an object is reset also all its children objects are automatically reset. The resetAll method undoes all modifications done to a collection, and to all its children collections. The resetAll method can be called only on collections with no father. move operations are undone, too if they are called on the updatesManager of the destination father.
  10. When the batch processing is terminated, call either the update, or the submit methods of just the updateManagers of the collections that have no father collections, since the updateManagers of all children collections are handled automatically by their fathers. Both the update and the submit methods send json data to the controller, but while update method use an ajax call, the submit method create a new form, fill it with the destinationViewModel data and do a standard submit, that, in turn, causes the browser page to change.
    The Mvc4 Client- Filtering -Paging -Sorting-updating file in the download area contain an example with an ApiController and with the update method. While the Advanced JSon Communication file in the download area contains examples with both update and submit, all with a standard Action Method.
    In case we call the submit or the update methods of several updatesManagers,  the arguments of these methods allows us to specify wich one of them acts as master: just the master takes care of actually sending the destinationViewModel to the server. This way several updates will be sent together to the server in a single destinationViewModel and with a single Http Post.
    As a default, communication with the server is done only if there are actual changes to submit in the master updatesManager or in some of its children updateManagers, but this behaviour can be changed by providing an updatingCallback in the updatesManager options. The updatingCallback can be used also to perform some custom processing before submitting the changes.
  11. The result of the call will contain possible server errors and possible newly created objects keys, that will be dispatched automatically in the right places. However, if some custom processing is needed we can specify an updatesCallback in the updatesManager options. The updateCallback is called before performing any errors or keys dispatching. Errors processing can be aborted by setting the setErrors property of the argument passed to the callback to false, while keys processing cannot since this would cause the desynchronization between server and client.
  12. Possible sever errors are shown automatically, but the last errors returned by the server are stored in case we need to refresh parts of the User Interface. Error refreshing of a form can be performed by calling the refreshErrors method of any updatesManager that was involved in the update. Error refreshing is usefull when:
    1. A new object is shown in a detail area and the errors of the old objects must be substituted with the errors of the new object.
    2. Changes done to an object are undone and, consequently, all errors associated to that object must be removed from the interface. The reset and resetAll methods automatically call the refreshErrors method on the form that is passed as argument, but one might need to call manually the refreshErrors, if errors must be removed also by other forms.

Below the possible options we can pass to the updatesManager with their default values:

 

            {
                updater: {u: "Modified", i: "Inserted", d: "Deleted", f: "FatherReferences"},
                updateCallback: function(e, result, status){},
                updatingCallback: function (changes, modelToPost, expr){return changes;},
                prepareCallback: function(item){},
                isoDate:false

            }

 

Where:

  • isoDate, is a boolean that specifies if date must be sent to the server in iso format, or in the format \/Date(...)\/. ApiControllers with the default serializer accepts iso dates, while standard Action Methods accepts the \/Date(...)\/ format.
  • objectKey: a boolean that informs the framework that the principal key is a complex object. The default is false.
  • updater, contains the names of the properties that will contain the collection that compose the change set. When the change set is automatically computed an object with the above properties is created, its properties are filled and it is placed in the place specified by destinationExpression within the destinationViewModel. if both destinationExpression and destinationViewModel are null the change set object is sent directly to the server without being inserted into another object. Its default is:{ u: "Modified", i: "Inserted", d: "Deleted", f: "FatherReferences" }. This default object matches the Updater<T, U> .Net object typically used to receive a change set on the controller side. Normally, there is no need to change the default value.
  • updateCallback is called as soon as a response is received from the server. 
    • status, is the Http status of the response.
    • result is the data object received from the server. It contains an errors property with the list of all server errors, and an insertedKeys properties with all keys returned by the server. The exact format of the data structures contained in these properties is unimportant for most of developers since both of them are handled automatically by the updatesManager. Anyway their format reflects the format of the server side .Net objects built on the server side that we will discuss in another paragraph.
    • e, is the object:
      { setErrors: true,  
      model: sourceViewModel,  
      expression: sourceExpression,  
      key: keyExpression,  
      success: !result.errors  }
      If setErrors is set to false within the callback, the automatic error processing is aborted.  However, all errors returned by the server are saved, and they can be shown at a later time by calling the method refreshErrors.
  • htmlStatusMessages: a function that is called in case the ajax call to the server returns an error, but the server doesn't return a list of errors in the errors property of a json response (see the standard response format in the updateCallback documentation). It is passed the Html statusCode as first argument and the associated statusText as second argument. It is expected to return the error message to display to the user. The default implementation returns the statusText.
  • updatingCallback, is called just before sending the updates to the server. Further processing is continued just if  it returns true. The arguments passed to this callback are:
    • changes, a boolean that is true if an only if there are actual updates either in the collection or in some children collection.
    • modelToPost, the object that is being sent to the server.
    • destinationExpression, the updatesManager destinationExpression that can be also null.
  • onUpdateComplete: a function that, if provided, is called at the end of the processing of the response received by the server. It is called just by not dependent updatesManagers, ant it is passed the same arguments as updateCallback.
  • prepareCallback, is called just after an object is prepared. It is passed as argument the object that has been prepared. It is a good place where to add some custom behaviour to all objects of the collection.
  • automodified: boolean option with a false default value. If true there is no need to declare  manually that an entity has been modified(by calling the modified method of the updatesManager), after some user editing. Setting this option to true, decrease the performance. 
  • dispose: a function that, if provided, is invoked immediately before an item is physycally deleted. That is, after that the server has confirmed the delete of an item that was previously declared logically deleted. It is passed the item that is being deleted.

Below, an example of prepareCallback. It is used to subscribe a function that calls automatically the updated method to all properties that the user can change:

 

    ClientToDoView.childUpdater.options({
        isoDate: true,
        prepareCallback: function (item) {
            var prev = false;
            function subscription() {
                ClientToDoView.childUpdater.modified(item, true, true);
                if (prev && !item._modified())
                    detailToDo.undoTask(item);
                prev = item._modified();
            };
            item.Name.subscribe(subscription);
            item.WorkingDays.subscribe(subscription)
        }

 

Handling updates on the server side.

For a quick start on this subject, please, read the tutorials:

Mvc Controls Toolkit Support to Mvc4 WebApi

Mvc Controls Toolkit Support to Mvc4 WebApi 2: Handling Relations

The ViewModel of the Action method or of the ApiController method that receives the updates from the master updatesManager must have the same structure of the destinationViewModel, if a destinationViewModel exists, otherwise it must have the same structure of a change set object. Since the names of the properties of the change set object can be configured in the updatesManager options, we are free to decide the overall structure of the destinatioViewModel. However, to help the development of the server side code the Mvc Controls Toolkit furnishes two .Net classes that can be used as change set objects, and whose property names are the default names: {u: "Modified", i: "Inserted", d: "Deleted", f: "FatherReferences"}.

The two classes are Updater<T, U>, and ChildUpdater<T, U>. The generics T and U are respectively the types of the collection objects, and of their keys. The Updater<T, U> can be used with collections that are not children of other collections, since it doesn't contain the FatherReferences property, while the ChildUpdater<T, U> class is specific for children collections.

Once the keys of the newly inserted elements of a collection of objects have been computed they can be used to update the external keys properties of any collection of children entities by calling the ImportExternals method of the ChildUpdater<T, U> instance that contains the change set of that children collection:

 

public void ImportExternals<L, S>(L[] externalKeys, Expression<Func<T,S>> expression)

 

 

The keys of the father entities are passed in the externalKeys array in the same order the original father entities were in the Inserted collection of their change set object. This way the ImportedExternals method, with the help of the FatherReferences collection, can find the right external key for each object. The ImportedExternals method is informed on the property where to copy the external keys through the expression lambda expression.

Below an example that shows the use of the ImportExternals method:

 

                    using (var t=new TransactionScope())
                    {
                        if (model != null && model.ToDoCS != null)
                        {
                            ToDoKeys = ToDoViewModel.UpdatePage(model.ToDoCS.Inserted, model.ToDoCS.Modified, model.ToDoCS.Deleted);

                            //imports the external keys of the newly created father entities into their children
                            if (model.TaskCS != null) model.TaskCS.ImportExternals(ToDoKeys, m => m.FatherId);
                            //here the same for other children collections
                        }
                        if (model != null && model.TaskCS != null)
                        {
                            TaskKeys=ToDoViewModel.UpdatePageTasks(model.TaskCS.Inserted, model.TaskCS.Modified, model.TaskCS.Deleted);
                        }
                        t.Complete();
                    }

 

The other side of the contract to be respected by the server is returning all server errors, and all keys created on the server. This job is automatically done by the ApiServerErrors<U> in ApiControllers, and by the ServerErrors<U> class in standard Action Methods. Using them is easy:

 

            // if keys have different simple types such as one is int, and one other is string, use ApiServerErrors<object>
            return new ApiServerErrors<int>(ModelState, 
                new ApiKeyInfos<int>[] {
                    new ApiKeyInfos<int>{destinationExpression="ToDoCS", keys=ToDoKeys},
                    new ApiKeyInfos<int>{destinationExpression="TaskCS", keys=TaskKeys}
                }).Wrap();

 

or

 

            // if keys have different simple types such as one is int, and one other is string, use ApiServerErrors<object>
            return new ServerErrors<int>(ModelState, 
                new KeyInfos<int>[] {
                    new KeyInfos<int>{destinationExpression="ToDoCS", keys=ToDoKeys},
                    new KeyInfos<int>{destinationExpression="TaskCS", keys=TaskKeys}
                });

 

The use of the two classes is completely analogous, the only difference beig that in the first case we called the wrap() method that add an appropriate Http Status code.

Possible errors are automatically extracted from the Modelstate that is passed as first argument.

ToDoKeys and TaskKeys are two arrays of keys. The keys must be placed in the arrays in the same order the original objects were received in the Inserted collections of their change sets.

"destinationExpression" is the destinationExpression that locates the original change set in the destinationViewModel.

In case we have just one change set we can use a simpler overload of the ApiServerErrors (or ServerErrors) constructor:

 

return new ApiServerErrors<int>(ModelState, insertedKeys).Wrap();

 

In case we need to return to the client further properties we can inherit from the ServerErrors and ApiServerErrors classes and add the needed property. In order to process the added properties on the client we can specify a custom updateCallback. Infact, the updateCallback receives the object returned by the server as one of its arguments.

Below the full code of the ApiController post method we used in the previous code snippets. The full code is contained in the Mvc4 Client- Filtering -Paging -Sorting-updating  and Advanced JSon Communication files in the download area:

 

        public HttpResponseMessage<ApiServerErrors<int>> Post(UpdataViewModel model)
        {
            //uncomment to experiment server side error handling
            //ModelState.AddModelError("ToDoCS.Modified[0].Name", "Fake error");
            //ModelState.AddModelError("TaskCS.Modified[0].Name", "Fake error1");
            int[] ToDoKeys=new int[0];
            int[] TaskKeys = new int[0]; ;
            if (ModelState.IsValid)
            {
                try
                {
                    using (var t=new TransactionScope())
                    {
                        if (model != null && model.ToDoCS != null)
                        {
                            ToDoKeys = ToDoViewModel.UpdatePage(model.ToDoCS.Inserted, model.ToDoCS.Modified, model.ToDoCS.Deleted);

                            //imports the external keys of the newly created father entities into their children
                            if (model.TaskCS != null) model.TaskCS.ImportExternals(ToDoKeys, m => m.FatherId);
                            //here the same for other children collections
                        }
                        if (model != null && model.TaskCS != null)
                        {
                            TaskKeys=ToDoViewModel.UpdatePageTasks(model.TaskCS.Inserted, model.TaskCS.Modified, model.TaskCS.Deleted);
                        }
                        t.Complete();
                    }
                    
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("", ex.Message);
                    return
                        new HttpResponseMessage<ApiServerErrors<int>>(
                            new ApiServerErrors<int>(ModelState, new ApiKeyInfos<int>[0]), System.Net.HttpStatusCode.InternalServerError);
                }
                
            }
            
            // if keys have different simple types such as one is int, and one other is string, use ApiServerErrors<object>
            return new ApiServerErrors<int>(ModelState, 
                new ApiKeyInfos<int>[] {
                    new ApiKeyInfos<int>{destinationExpression="ToDoCS", keys=ToDoKeys},
                    new ApiKeyInfos<int>{destinationExpression="TaskCS", keys=TaskKeys}
                }).Wrap();
        }

 

Format of the FatherReferences property

Since father newly Inserted objects have no keys,  the external key properties their children objects cannot be used to reference the father object, so the father objects are identified  simply by their positions in the Inserted collection that is contained in the fathers change set.  The element at position l of the FatherReferences list contains the position of the father of the child element at position l in the list of all children objects created on the client. However, we don't need to take care of this because the ImportExternals method do all job of updating the external keys with the newly created keys for us.

updatesManager methods reference.

options(o): Pass a new option object to the update manager

addChildUpdateManager(options): Add a child update manager. See the introduction on the updatesManager for the format of options.

prepare:(entities, track): prepare the array of objects or the single object contained in entities. If track is true, changes tracking is enabled for the prepared objects. 

unprepare:(entities): undoes all modifications done by the prepare method to the array of objects or the single object contained in entities

refreshErrors(jForm, [errorState], [prefixToRemove]): refreshes the errors on the on the form contained in the jQuery object jForm. errorState can be either null or a result returned by the server. If it is null the last errors returned by the server are used. Normally prefixToRemove should not be used by the developer, since its effects are automatically achieved by other methods. prefixToRemove can be either an object or a string expression. If prefixToRemove is a string all errors whose prefix starts with prefixToRemove are removed from the stored list of all errors returned by the server before refreshing the form. If prefixToRemove is an object all errors associated to that object are removed from the stored list of all errors returned by the server before refreshing the form.

clearErrors(jForm, [resetLastErrors=false]): clears jForm (jQuery object containing a form) from all its errors. If resetLastErrors is true the stored list of all errors returned by the sever is cleared.

modified(item, [track=false], [immediateTrack=false]): mark the object item as modified. If immediateTrack is true an actual check of all object properties is performed to verify if the objecti was actually modified, and the result of the check is assigned to the _modified observable property of the object. If immediateTrack is false the _modified observable property of the object is set to true, and the actual check of all modifications is delayed till the computation of the change set.
If track is true, and changes tracking has not been activated for the entity, changes tracking will be activated.

inserted(array, item): marks item as a new inserted object, that is sets its observable property _inserted to true, and adds it to the array array.

deleted(array, item): marks as deleted the object item contained in the array array. If the object is a newly inserted object it is simply removed from array, otherwise it is logically marked as deleted by setting its _destroy  property (it is not an observable property) to true. Logically deleted objects automatically disappears from the user interface (see here).

hasChanges(): return true if there are pending changes to be sent to the server. 

addChild(item, propertyExpression, child, [isNew=false], [overrideKeyExpression=false]): add child as child of item, iserting it in the array contained in the property of item specified by the string expression propertyExpression. The key of item is automatically copied in the external key property of child. If overrideKeyExpression is specified it is used instead of the expressionKey of the update manager. If child was not yet prepared it is automatically prepared. If isNew is true child is marked as newly inserted. If child was a child of another object, please remember to remove it from the array it was in, before adding it as a child of another object.

moveChild(fromCollection, newFather, newPropertyExpression, child,  [overrideKeyExpression=null], [addAfterSibling=false], [sibling, = null], [before=false]) : it move the child entity child, contained in the observable array fromCollection,  from its old father that owns oldCollection, to the observable collection contained in the property of newFather that is specified by the string expression newPropertyExpression. This operation is undone if all changes of newFather are undone. If addAfterSibling is false, child is added at the end of the target collection. If  addAfterSibling is true but sibling is null, child is added as first child of its target collection. Finally, if  addAfterSibling is true and sibling is not null child is added either immediately before or immediately after sibling, according to the value of beforeIf overrideKeyExpression is not null, the property specified by this expression substitutes the key of child in the comparisons to verify if two entities are the same entityfromCollection may belong also to an entity set handled by a different updatesManager, thus enabling child movements between different controls.

reset(item, [jForm], [array]): undoes all changes done to the object item contained in the array array, if changes tracking was enabled on item. If array is not provided the array specified by propertyExpression is used. Errors associated to item are removed from the stored list of all errors returned by the server and if jForm is provided and is different from null its error state is automatically refreshed.

accepted(item): all changes done to item are acceped. This means, the old values are updated to the actual values of the object. After that changes tracking continues as before. The accepted method is automatically called once the updates have been succesfully submitted to the server. If the server returns errors, the updatesManager assumes that the changes were not accepted by the server, and accordingly, it doesn't call the accepted method. Normally, the developer should not call directly the accepted method, since this would cause a desynchronization between server and client.

update(jErrorForm [,isDependent=false] [,dependentRequests] [, startDependents]): trigger the server ajax update. jErrorForm is a jQuery object containing the form to refresh with the errors received by the server. If there are other forms that can be affected by these errors their refresh can be called manually within the updateCallback. If the updatesManager rhas children their update is triggered automatically, by causing all of them to compute their change set and inserte them into the destinationViewModel that will be sent to the server. Once the response of the server is received the the updateCallback of all children is invoked automatically.
If there are several father collections that need to send their updates to the server in with the same post request and with the same destinationViewModel, we need to call the update method of all of them, but just one call will have the isDependent argument set to true: the last call performed! More specifically, just one updatesManager will work as a master and will take care of sending the destinationViewModel to the server, the other ones will just put their changes sets into the destinationViewModel. The master updatesManager will be the last one to call the update method and will be the only one passing it true as value for isDependent.
The master updatesManager needs to pass also an array containing all other updatesManager involved in the update as third argument of update. If startDependents is true the master takes care of calling the update method of all its dependents updatesManagers.

submit(jForm, isDependent  [, startDependents): Sends all updates to the server with a normal browser post that will cause a page change. It works as the update method, the only difference being that the fourth argument is completely absent.  In fact, if the array  dependentRequest is not empty the submit method of all dependent updatesManager is called automatically. A code sample showing the use of the submit method is contained in the Advanced JSon Communication file in the download area.

arrayChanged(observableArray): returns a computed observable whose value is true if and only if at least one object in the observable array observableArray has been marked as modified, or if some object was deleted or inserted in observableArray. For an example of use of this method refer to the tutotial: Mvc Controls Toolkit Support to Mvc4 WebApi 2: Handling Relations.

addRelated(collectionExpression, entities, entitiesExternalExpression, inverseCollectionExpression, overrideKeyExpression): it is usefull to handle many-to-many relations. It computes all mutual references existing between the items of two related collections by using key and external key information:

  • entities is the array(or ko observable array) with the collection we would like to relate with the collection handled by the current instance of the updateManager.
  • collectionExpression is a string expression specifying the array contained in each entity of the collection handled by the current instance of the updateManager,  where the pointers to the related entities will be pushed. If the array doesn’t exists it is created, it it already exists it is not cleared.
  • entitiesExternalexpression is a string expression that locates the external key within each entity of the entities collection.
  • inverseCollectionExpression is a string expression specifying the array contained in each entity of the entities collection where the pointers to the related entities will be pushed. If the array doesn’t exists it is created, if it already exists it is not cleared.
  • overrideKeyexpression, if provided, is used in place of the key defined in the current instance of the updateManager.

For some hints on how to handle many-to-many relation refer to the end of the tutorial: Mvc Controls Toolkit Support to Mvc4 WebApi 2: Handling Relations.

 

 

Last edited Jun 22, 2014 at 10:45 AM by frankabbruzzese, version 21

Comments

No comments yet.