微风从现有实体创建实体
Breeze create entity from existing one
我已经连续几天头疼了。
想象一下你有一个汽车销售管理应用程序。你卖不同的型号。您的车型有50个特性。举个例子,假设你想卖掉布加迪威龙。现在,你刚刚收到了其中的5辆车。所以,我登录到我的应用程序,用特定的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,但这个破解的解决方案忽略了它们,这是可以改进的,但目前我自己用几个.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);
});
}
接受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
检测,并使用以下内容来复制Junction表:
var fk = false;
navProp.entityType.foreignKeyProperties.forEach(function (singleProperty) {
if (singleProperty.relatedNavigationProperty.entityTypeName == newItem.entityType.name)
fk = singleProperty.name;
});
if (!fk) return;
我使用了Ward的原始代码(没有子克隆部分),并添加了以下代码,因此它递归地删除了complexAspect(我有一个由两个嵌套的复杂属性组成的地理属性):
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);
}
此外,我自己也不解析exportEntitys中的JSON,而是使用了该选项(我想这是后来添加的)。
- 创建一个类似链接的按钮,并通过Javascript函数打开一个新的弹出窗口
- 为effect Composer创建GodRays效果过程
- 从javascript创建一个列表
- 微风从现有实体创建实体
- 如何在phantomjs中创建实体
- 创建Crafty JS实体的类(类的类?)
- 用于使用 DateTime 创建新实体的 API 控制器
- 是否可以捕获内部创建的必应地图实体的事件
- 创建来自 Twitter REST API 实体(主题标签、链接、提及等)的推文文本的链接
- Knockout.js toJSON 从 Breeze 实体创建空对象
- 如何在javascript中创建实体
- 通过选择框创建实体
- 依靠其他实体在微风中创建实体
- 基于实体属性值创建数据网格
- 创建新实体时用javascript刷新视图
- 如何在JHipster 3.x中创建具有相关实体列表的实体视图
- 无法识别微风创建实体类型
- SAPUI5创建带有日期的OData实体——生成以CX_SXML_PARSE_ERROR结束的错误请求负载
- 在不修改/创建实体记录的情况下触发插件
- 基于数据库实体创建模型