Breeze creates an object from an existing

I have been banging my head for several days.

Imagine you have a car sales management application. You sell different models. Your car model has 50 objects. For example, suppose you want to sell a Bugatti Veyron. Now you have just received 5 of these cars. So, I enter my application, create the first Bugatti Veyron with a specific identifier. Then I want to add a second one, but there is a problem - I will have to write down all these properties again! I would like to have a Copy button, and I would just change the serial number, the breeze would change the identifier and voila, two cars there!

For hacking, I first created this solution:

newCar(datacontext.createCar());
newCar().property1(oldCar().property1());
newCar().property2(oldCar().property2());
...

It was ugly, and after I proved that I can do it, of course, the request for the application was to do everything with the ability to copy - I would not do that! There must be a copy somewhere. After digging through many things, even trying to change some things in the wind, I could not do something like:

manager.createEntity('Car', oldCar);

Now the last solution is a little more viable than the first, but still requires more code than I would like, and not as intuitively as it could be:

        var newObject = {};
        manager.metadataStore._structuralTypeMap[oldCar.entityType.name].dataProperties.forEach(function (singleProperty) {
                if (!singleProperty.isPartOfKey)
                newObject[singleProperty.name] = oldCar[singleProperty.name];
            });
        var newCar = manager.createEntity('Equipment', newObject);

Is there another “clean” way to create a new object with exactly the same properties, but, of course, a different identifier?

I should mention that there are some ICollections in the Car object, but this hack-ish solution ignores them, which can be improved, but I am currently processing it myself with several for.Ee loops.

+4
5

​​ . , . promises .

, . , Breeze EntityManager.exportEntities , . , , .

( , ):

function cloneItem(item) {
    // export w/o metadata and then parse the exported string.
    var exported = JSON.parse(manager.exportEntities([item], false));
    // extract the entity from the export
    var type = item.entityType;
    var copy = exported.entityGroupMap[type.name].entities[0];
    // remove the entityAspect
    delete copy.entityAspect; 
    // remove the key properties
    type.keyProperties.forEach(function (p) { delete copy[p.name]; });

    // the "copy" provides the initial values for the create
    return manager.createEntity(type, copy);
}

, , , , , .

, . , . , . .

15 2013

, ( ). , , :

cloneItem(something, ['collectionProp1', 'collectionProp2']); 

, ,

:

function cloneItem(item, collectionNames) {
    var manager = item.entityAspect.entityManager;
    // export w/o metadata and then parse the exported string.
    var exported = JSON.parse(manager.exportEntities([item], false));
    // extract the entity from the export
    var type = item.entityType;
    var copy = exported.entityGroupMap[type.name].entities[0];
    // remove the entityAspect (todo: remove complexAspect from nested complex types)
    delete copy.entityAspect;
    // remove the key properties (assumes key is store-generated)
    type.keyProperties.forEach(function (p) { delete copy[p.name]; });

    // the "copy" provides the initial values for the create
    var newItem = manager.createEntity(type, copy);

    if (collectionNames && collectionNames.length) {
        // can only handle parent w/ single PK values
        var parentKeyValue = newItem.entityAspect.getKey().values[0];
        collectionNames.forEach(copyChildren);
    }
    return newItem;

    function copyChildren(navPropName) {
        // todo: add much more error handling
        var navProp = type.getNavigationProperty(navPropName);
        if (navProp.isScalar) return; // only copies collection navigations. Todo: should it throw?

        // This method only copies children (dependent entities), not a related parent
        // Child (dependent) navigations have inverse FK names, not FK names
        var fk = navProp.invForeignKeyNames[0]; // can only handle child w/ single FK value
        if (!fk) return; 

        // Breeze `getProperty` gets values for all model libraries, e.g. both KO and Angular
        var children = item.getProperty(navPropName);
        if (children.length === 0) return;

        // Copy all children
        var childType = navProp.entityType;
        children = JSON.parse(manager.exportEntities(children, false));
        var copies = children.entityGroupMap[childType.name].entities;

        copies.forEach(function(c) {
            delete c.entityAspect;
            // remove key properties (assumes keys are store generated)
            childType.keyProperties.forEach(function (p) { delete c[p.name]; }); 
            // set the FK parent of the copy to the new item PK               
            c[fk] = parentKeyValue;
            // merely creating them will cause Breeze to add them to the parent
            manager.createEntity(childType, c);
        });
    }
+9

Took Wards , .

cloneEntity(someEntity, ['collectionProp1.subCollection.another', 'collectionProp2']); 

, .

function cloneEntity(item, collectionNames) {
    var manager = item.entityAspect.entityManager;

    // export w/o metadata and then parse the exported string.
    var exported = JSON.parse(manager.exportEntities([item], false));

    // extract the entity from the export
    var type = item.entityType;
    var copy = exported.entityGroupMap[type.name].entities[0];

    // remove the entityAspect (todo: remove complexAspect from nested complex types)
    delete copy.entityAspect;

    // remove the key properties (assumes key is store-generated)
    type.keyProperties.forEach(function (p) { delete copy[p.name]; });

    // the "copy" provides the initial values for the create
    var newItem = manager.createEntity(type, copy);

    if (collectionNames && collectionNames.length) {
        // can only handle parent w/ single PK values
        var keyValue = newItem.entityAspect.getKey().values[0];
        collectionNames.forEach(function (propertyString) { copyChildren(item, propertyString, keyValue); });
    }
    return newItem;

    function copyChildren(parentItem, navPropString, parentKeyValue) {

        var navPropName;
        // todo: add much more error handling
        var parentType = parentItem.entityType;

        //parse deep properties
        if (navPropString.indexOf('.') >= 0) {
            navPropName = navPropString.substr(0, navPropString.indexOf('.'));
            navPropString = navPropString.substr(navPropString.indexOf('.') + 1);
        } else {
            navPropName = navPropString;
            navPropString = "";
        }

        var navProp = parentType.getNavigationProperty(navPropName);

        if (navProp.isScalar) return; // only copies collection navigations. Todo: should it throw?

        // This method only copies children (dependent entities), not a related parent
        // Child (dependent) navigations have inverse FK names, not FK names
        var fk = navProp.invForeignKeyNames[0]; // can only handle child w/ single FK value
        if (!fk) return;

        // Breeze `getProperty` gets values for all model libraries, e.g. both KO and Angular
        var children = parentItem.getProperty(navPropName);
        if (children.length === 0) return;

        // Copy all children
        var childType = navProp.entityType;
        var copies = JSON.parse(manager.exportEntities(children, false)).entityGroupMap[childType.name].entities;

        copies.forEach(function (c) {

            //Get the original childid for deeper copy
            var originalChildId = c.id;

            delete c.entityAspect;

            // remove key properties (assumes keys are store generated)
            childType.keyProperties.forEach(function (p) { delete c[p.name]; });

            // set the FK parent of the copy to the new item PK               
            c[fk] = parentKeyValue;

            // merely creating them will cause Breeze to add them to the parent
            var childItem = manager.createEntity(childType, c);

            if (navPropString.length > 0) {
                //Copy children

                var originalChild = $.grep(children, function (a) {
                    return a.id() == originalChildId;
                })[0];

                var childKeyValue = childItem.entityAspect.getKey().values[0];
                copyChildren(originalChild, navPropString, childKeyValue);
            }
        });
    }
};
+1

, . Ward cloneItem() ,

children.entityGroupMap childType.name.

, copyChildren():

            .....
        // Copy all children
        var childType = navProp.entityType;
        children = JSON.parse(manager.exportEntities(children, false));

        var copies;
        if (children.entityGroupMap.hasOwnProperty(childType.name)) {
            copies = children.entityGroupMap[childType.name].entities;
            copyChildrenOfType(copies, childType);
        }
        else {
            childType.subtypes.forEach(function (subtype) {
                if (children.entityGroupMap.hasOwnProperty(subtype.name)) {
                    copies = children.entityGroupMap[subtype.name].entities;
                    copyChildrenOfType(copies, subtype);
                }
            });
        }
        function copyChildrenOfType(copies, childType) {
            copies.forEach(function (c) {
                delete c.entityAspect;
                // remove key properties (assumes keys are store generated)
                childType.keyProperties.forEach(function (p) { delete c[p.name]; });
                // set the FK parent of the copy to the new item PK               
                c[fk] = parentKeyValue;
                // merely creating them will cause Breeze to add them to the parent
                manager.createEntity(childType, c);
            });
        }
+1

, - , , , :

    function createSimpleObject(heavyObject) {
        if (heavyObject === undefined) return {};
        var simpleObject = {};
        manager.metadataStore._structuralTypeMap[heavyObject.entityType.name].dataProperties.forEach(function (singleProperty) {
            if (!singleProperty.isPartOfKey)
                simpleObject[singleProperty.name] = heavyObject[singleProperty.name]();
        });
        return simpleObject;
    }

    function makeNavigationProperties(newObject, oldObject, navigationProperties) {
        if (oldObject === undefined || navigationProperties === undefined) return {};
        navigationProperties.forEach(function (singleNavigationProperty) {
            var selectedArray = [];
            if (ko.isObservable(oldObject[singleNavigationProperty])) {
                selectedArray = oldObject[singleNavigationProperty]();
            }
            else selectedArray = oldObject[singleNavigationProperty];
            if (selectedArray) {
                selectedArray.forEach(function (singleObject) {
                    var simpleObject = {};
                    manager.metadataStore._structuralTypeMap[singleObject.entityType.name].dataProperties.forEach(function (singleProperty) {
                        if (!singleProperty.isPartOfKey) {
                            if (singleProperty.relatedNavigationProperty) {
                                if (singleProperty.relatedNavigationProperty.entityTypeName === oldObject.entityType.name) {
                                    simpleObject[singleProperty.name] = newObject.id();
                                }
                                else {
                                    if (ko.isObservable(singleObject[singleProperty.name]))
                                        simpleObject[singleProperty.name] = singleObject[singleProperty.name]();
                                    else simpleObject[singleProperty.name] = singleObject[singleProperty.name];
                                }
                            }
                            else {
                                if (ko.isObservable(singleObject[singleProperty.name]))
                                    simpleObject[singleProperty.name] = singleObject[singleProperty.name]();
                                else simpleObject[singleProperty.name] = singleObject[singleProperty.name];
                            }
                        }
                    });
                    manager.createEntity(singleObject.entityType.shortName, simpleObject);
                });
            }
        });
    }

, :

function createMyObject(originalObject, navigationProperties){
    var newMyObject = manager.createEntity('MyObject', createSimpleObject(originalObject));
    makeNavigationProperties(newMyObject, originalObject, navigationProperties);
    return newMyObject;
}

, , , :

copiedObject(datacontext.createMyNewObject(originalObject(), ['navigationProperty1', 'navigationProperty2', 'navigationProperty3']));

copiedObject , , originalObject - , , , . , , . , ​​ .

! , , fk :

var fk = false;
navProp.entityType.foreignKeyProperties.forEach(function (singleProperty) {
if (singleProperty.relatedNavigationProperty.entityTypeName == newItem.entityType.name)
    fk = singleProperty.name;
});
if (!fk) return;
0

I used the Ward source code (without the clone part for children) and added the following code to it so that it would delete complexAspect recursively (I had a geography attribute consisting of two nested complex properties):

CloneEntity: function (originalEntity) {
    // NoRyb change
    function recursiveFixEntity(entity) {
        if (entity && (typeof entity === 'object')) {
            delete entity.complexAspect;
            for (var propertyName in entity) {
                recursiveFixEntity(entity[propertyName]);
            }
        }
    };

    var manager = originalEntity.entityAspect.entityManager;
    // export w/o metadata and then parse the exported string.
    var exported = manager.exportEntities([originalEntity], { asString: false, includeMetadata: false });
    // extract the entity from the export
    var type = originalEntity.entityType;
    var copy = exported.entityGroupMap[type.name].entities[0];
    // remove the entityAspect
    delete copy.entityAspect;
    // remove the key properties
    type.keyProperties.forEach(function (p) { delete copy[p.name]; });

    // NoRyb change:
    recursiveFixEntity(copy);

    // the "copy" provides the initial values for the create
    return manager.createEntity(type, copy);
}

Also, I do not parse JSON from exportEntities myself, I used the parameter instead (I think it was added later).

0
source

All Articles