簡體   English   中英

Breeze從現有實體創建實體

[英]Breeze create entity from existing one

我已經好幾天了。

想象一下,你有一個汽車銷售管理應用程序。 你賣不同的型號。 您的汽車模型有50個屬性。 僅舉例來說,假設你想賣掉布加迪威龍。 現在,你剛收到5輛這樣的車。 所以,我登錄我的應用程序,創建第一個具有特定ID的Bugatti Veyron。 然后我想添加第二個,但有一個問題 - 我將不得不再次寫下所有這些屬性! 我想要一個復制按鈕,我只是更改序列號,微風會改變ID和瞧,那里有兩輛車!

為了黑客的緣故,起初我創建了這個解決方案:

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

它很難看,經過我的證明我可以做到,當然,請求申請是為了讓所有東西都可以復制 - 我不會這樣做! 某處必須有副本。 在挖掘了很多東西后,甚至試圖在微風中改變一些東西,我做不了類似的事情:

manager.createEntity('Car', oldCar);

現在,最新的解決方案比第一個解決方案更可行,但仍然需要比我想要的更多的代碼,並且不像它那樣直觀:

        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);

有沒有其他“更清潔”的方法來制作具有完全相同屬性的新實體,但當然,不同的ID?

我應該提到Car實體中有一些ICollections,但是這個hack-ish解決方案忽略了可以改進的那些,但是目前我自己處理了一些.forEach循環。

我們正在后面的房間做這樣的事情。 我們會在准備好的時候通知您。 沒有承諾或時間。

與此同時,我對它采取了一個裂縫。 我決定利用Breeze EntityManager.exportEntities方法知道如何克隆實體這一事實。 如果您閱讀該方法的breeze源代碼,您就會知道它很棘手。

這就是我提出的(作為平民,而不是Breeze開發人員):

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);
}

與您的一樣,它保留了外鍵屬性,這意味着如果源具有這樣的值,則父實體的引用導航屬性將具有從緩存中提取的值。

與您的一樣,不會填充集合導航屬性。 此方法不知道如何克隆子項。 它不應該是不言而喻的。 這對你來說是額外的功勞。

2013年12月15日更新

因為你問過,我已經重新實現了克隆孩子的能力(收集導航)。 我已經按照您建議的語法進行操作,因此用法如下:

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

請注意,我再次依靠Breeze導出進行繁重的工作

警告 :此代碼非常脆弱,並不適用於所有型號

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's PK               
            c[fk] = parentKeyValue;
            // merely creating them will cause Breeze to add them to the parent
            manager.createEntity(childType, c);
        });
    }

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's 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);
            }
        });
    }
};

我的導航屬性具有子類型 ,在創建對象時手動創建。 使用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's PK               
                c[fk] = parentKeyValue;
                // merely creating them will cause Breeze to add them to the parent
                manager.createEntity(childType, c);
            });
        }

雖然Breeze團隊正在研究它,如果有人在完成之前就需要這個,那么這里是我編寫的用於制作對象副本及其導航屬性的代碼:

    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;

我使用了Ward的原始代碼(沒有子代克隆部分)並添加了以下代碼,因此它遞歸地刪除了complexAspect(我有一個Geography-Attribute,它由兩個嵌套的復雜屬性組成):

CloneEntity: function (originalEntity) {
    // NoRyb's 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's change:
    recursiveFixEntity(copy);

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

此外,我不會自己解析來自exportEntities的JSON,而是使用了該選項(我猜這是后來添加的)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM