Breeze - Lazy加载复杂类型

时间:2013-10-09 15:44:20

标签: javascript breeze

我试图在微风中懒惰地加载一个复杂的类型,但无法找到实现这一目标的方法。

我想使用复杂类型而不是导航方式的原因是我必须使用的服务不是像微风一样进行CRUD。我必须将一个带有所有子对象(标量和非标量)的单个对象发送到负责存储数据的单个服务方法(插入/更新/删除)。

我尝试使用导航属性执行此操作,但这意味着我必须创建一个实体数组以发送到API控制器,然后重新创建整个对象。这将是困难的,但更是如此,因为在子对象中没有外键(在我直到现在看到的所有样本中都是这种情况)使得再次映射它们变得很痛苦。

对于复杂的类型,我没有这个问题(或者我不知道)。

我必须使用这样的对象结构:

1.Parent:产品(类)

1.1Child:packages(array)

1.2Child:splitLevels(array)

1.2.1Grandchild:权限(数组)

1.2.1.1Grandgrandchild:药店(数组)

1.2.2Grandchild:splitLevel(class)

包与产品一起加载,这很好用。 Howevers,splitLevels不包含在此datacontract中(因为它需要太多数据,并且不会经常查阅)。在请求此数据时,会向产品添加一个布尔值以指示它们已被加载,从那时起它也需要将它们发送到服务器。

加载产品时,会出现问题: Object不支持属性或方法'getProperty'

这是由breeze中的_initializeInstance方法引起的:

if (initFn) {
    if (typeof initFn === "string") {
        initFn = instance[initFn];
    }
    initFn(instance);
}
this.complexProperties && this.complexProperties.forEach(function (cp) {
    var ctInstance = instance.getProperty(cp.name);
    cp.dataType._initializeInstance(ctInstance);
});

该实例为空,无法从中获取任何属性。

有什么方法可以解决这个问题吗? 有没有办法在不获取多个实体的情况下使用导航属性;所以我可以不使用它来发送单个对象:

if (product.entityAspect.entityState.isUnchanged()) {
    product.entityAspect.setModified();
}

// Packages
var entitiesToSave = product.packages().slice();// copy

// Split Levels
if (product.storeSplitLevels) {
    product.splitLevelsLoaded(true);
    // TODO: Add split levels to entities to save
}

// Product Details
entitiesToSave.push(product);

2 个答案:

答案 0 :(得分:1)

我按照您的建议创建了自定义捆绑包。

对于具有相同问题的其他开发人员,我做了以下事项:

  1. 创建一个自定义展开函数,该函数提供与breeze中的展开函数相同的功能,但也将其扩展为包含导航属性。

  2. 添加一个方法以从实体创建保存包。

  3. 代码:

    function createEntitySaveBundle(entity) {
        var rawEntity = unwrapInstance(entity);
        var entities = [];
        rawEntity.entityAspect = {
            entityTypeName: entity.entityType.name,
            defaultResourceName: entity.entityType.defaultResourceName,
            entityState: entity.entityAspect.entityState.name,
            autoGeneratedKey: {
                propertyName: entity.entityType.keyProperties[0].nameOnServer,
                autoGeneratedKeyType: entity.entityType.autoGeneratedKeyType.name
            }
        };
        entities.push(rawEntity);
    
        return { entities: entities, saveOptions: {} };
    }
    
    function unwrapInstance(entity) {
        var rawObject = {};
        var stype = entity.entityType || entity.complexType;
        var val;
        var entities;
    
        stype.dataProperties.forEach(function (dp) {
            if (dp.isUnmapped) {
                val = entity.getProperty(dp.name);
                val = transformValue(val, dp, false);
                if (val !== undefined) {
                    rawObject.__unmapped = rawObject.__unmapped || {};
                    // no name on server for unmapped props
                    rawObject.__unmapped[dp.name] = val;
                }
            } else if (dp.isComplexProperty) {
                if (dp.isScalar) {
                    rawObject[dp.nameOnServer] = unwrapInstance(entity.getProperty(dp.name));
                } else {
                    entities = entity.getProperty(dp.name);
                    rawObject[dp.nameOnServer] = entities.map(function (co) { return unwrapInstance(co); });
                }
            } else if (dp.isDataProperty) {
                val = entity.getProperty(dp.name);
                val = transformValue(val, dp);
                if (val !== undefined) {
                    rawObject[dp.nameOnServer] = val;
                }
            }
        });
    
        stype.navigationProperties.forEach(function (np) {
            if (np.isScalar) {
                // Doesn't occur with products, enabling this results in an endless loop without checking if the navigation property already exists in the rawObject (recursive..)
                // rawObject[np.nameOnServer] = unwrapInstance(entity.getProperty(np.name));
            } else {
                entities = entity.getProperty(np.name);
                rawObject[np.nameOnServer] = entities.map(function (eo) { return unwrapInstance(eo); });
            }
        });
    
        return rawObject;
    }
    function transformValue(val, prop) {
        if (prop.isUnmapped) return;
        if (prop.dataType === breeze.DataType.DateTimeOffset) {
            // The datajs lib tries to treat client dateTimes that are defined as DateTimeOffset on the server differently
            // from other dateTimes. This fix compensates before the save.
            val = val && new Date(val.getTime() - (val.getTimezoneOffset() * 60000));
        } else if (prop.dataType.quoteJsonOData) {
            val = val != null ? val.toString() : val;
        }
        return val;
    }
    

答案 1 :(得分:0)

如果没有更多信息,我并不完全清楚你要问的是什么,但我们正在计划为EntityManager的Breeze API添加一个函数,它允许你用任意数据结构调用任意端点并得到结果调用(如果有的话)通过JsonResultsAdapter合并回EntityManager。

在此之前,您可以通过绕过EntityManager.saveChanges并直接使用Breeze ajax适配器来调用您的端点来完成其中的一些操作。像

这样的东西
var ajaxImpl = breeze.config.getAdapterInstance("ajax");
ajaxImpl.ajax({
        type: "POST",
        url: url,
        dataType: 'json',
        contentType: "application/json",
        data: bundle,   // arbitrary data to server.
        success: function (httpResponse) {
            // perform custom client side code 
        },
        error: function (httpResponse) {

        }
    });