【问题标题】:Breeze - Lazy load complex typeBreeze - 延迟加载复杂类型
【发布时间】:2016-04-15 00:28:15
【问题描述】:

我正在尝试在微风中延迟加载复杂类型,但无法找到实现此目的的方法。

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

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

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

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

1.Parent:产品(类)

1.1Child:包(数组)

1.2Child:splitLevels(数组)

1.2.1孙:权限(数组)

1.2.1.1孙子:药店(数组)

1.2.2孙:splitLevel(类)

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

加载产品时,这会导致问题: 对象不支持属性或方法“getProperty”

这是由微风中的_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);

【问题讨论】:

    标签: javascript breeze


    【解决方案1】:

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

    对于遇到相同问题的其他开发人员,我做了以下操作:

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

    2. 添加从实体创建保存包的方法。

    代码:

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

    【讨论】:

      【解决方案2】:

      如果没有更多信息,我并不完全清楚您的要求,但我们计划为 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) {
      
              }
          });
      

      【讨论】:

      • 对不起,我的问题是: 1. 是否可以延迟加载嵌套的复杂类型;是一个包含复杂类型的数组,其中包含其他复杂类型。我无法让它工作(cfr 来自微风的代码块)。 2. 如果没有,有没有一种方法可以使用导航属性,而不需要所有实体处于同一级别,但传入数据合同定义它们的方式相同。但你实际上用你的评论回答了这个问题。
      猜你喜欢
      • 2018-03-09
      • 1970-01-01
      • 2011-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-12
      • 2012-04-20
      • 1970-01-01
      相关资源
      最近更新 更多