【问题标题】:Newly added entity is not showed correctly in my foreach knockout loop在我的 foreach 淘汰赛循环中未正确显示新添加的实体
【发布时间】:2013-08-25 10:36:35
【问题描述】:

我使用 Breeze 处理一个 asp.net mvc 项目。

我有一个页面,其中显示有关传输的详细信息,并在其下方的表格中列出链接的传输。

考虑以下实体:

public class Transport
{
    [Key]
    public int Id { get; set; }
    public string TransportNumber { get; set; }
    public string Description { get; set; }
    public virtual List<LinkedTransport> LinkedTransports { get; set; }
    ...
}

public class LinkedTransport
{
    [Key, Column(Order = 0)]
    public int TransportId { get; set; }
    [Key, Column(Order = 1)]
    public int TransportRelatedId { get; set; }

    public virtual Transport Transport { get; set; }
    public virtual Transport TransportRelated { get; set; }
}

所以这两个实体允许我定义我的传输和(对于每个)链接的传输。

首先,我将我的(主要)传输加载到一个名为 transport 的 observable 中:

var query = entityQuery.from('Transports')
                       .where('id', '==', transportId)
                       .expand("LinkedTransports.transportRelated");
query = query.using(breeze.FetchStrategy.FromServer);

请注意expand,我在其中还检索了链接的传输。

现在我有以下代码来显示我的传输和链接传输:

<div data-bind="with: transport()">
    <input type="text" data-bind="text: transportNumber"></input>
    <input type="text" data-bind="value: description"></input>       
    ...
    <table data-bind="foreach: linkedTransports">
        <tr>
            <td data-bind="text: transportRelated().transportNumber()"></td>
            <td data-bind="text: transportRelated().description()"></td>
        </tr> 
    </table>
</div>

到目前为止,一切都很好。我可以显示我的主要运输信息以及链接的运输信息。现在我需要让用户添加一些链接的传输。所以我有以下代码:

var createLinkedTransport = function (transpId, transpRelatedId) {

    var initialValues = ({
        transportId: transpId,
        transportRelatedId: transpRelatedId
    });

    manager.createEntity(entityNames.linkedTransport, initialValues);
};

在运行时,当我调用此函数时,我可以将链接的传输添加到我的(主)传输中。

我的问题:在我的 foreach 淘汰赛循环中未正确显示添加的元素。我看到表中添加了一个新行,但这一行是空的。我认为问题在于我没有expand 任何关于我新添加的元素的信息,但我不知道如何继续。

知道如何进行吗?


更新

需要明确的是,当我将linkedTransport 添加到我的传输后,在添加之后(并且不重新加载页面)我无法读取目标(*)linkedTransport 的属性。但是如果我保存更改并重新加载我的页面,那么我可以读取目标链接传输的属性。

当我说“目标链接传输”时,我指的是由我的 TransportRelatedId (>> public virtual Transport TransportRelated) 引用的传输。

所以如果我将linkedTransport #123 添加到传输#456 THEN 立即(不重新加载页面)我无法显示#123 的Description 属性.

<div data-bind="with: transport()">
    ...
    <div data-bind="foreach: linkedTransports">
        <label data-bind="text: transportRelated().description()"></label>
    </div>
</div>

希望我很清楚。


更新 2

按照 Ward 的建议,我在添加 linkedTransports 后立即设置断点并检查 transport().linkedTransports()。结果如下:

  • transport().linkedTransports()[0].transport() >> 属性在那里
  • transport().linkedTransports()[0].transportId() >> 1
  • transport().linkedTransports()[0].transportNumber >> '123456'(“虚拟”属性,没有帮助)
  • transport().linkedTransports()[0].transportRelated() >> null
  • transport().linkedTransports()[0].transportRelatedId() >> 5(linkedTransport的id)

所以我的问题是transportRelated() 为空。


更新 3

我终于让它工作了。在添加时将添加的(引用的)元素保存在缓存中是很重要的。对于我的情况,我会这样做:

ctxTransport.getTransportById(5, obs);
ctxTransport.createLinkedTransport(1, 5);

所以在调用createLinkedTransport 之前,我使用第5 个id(linkedTransport 的id)调用getTransportById

另一件重要的事情是我们如何在页面上显示linkedTransports:

<div data-bind="foreach: linkedTransports">                        
    <span class="input-control text">
        <!-- ko with: transportRelated -->
        <a href="#" class="fg-color-darken" data-bind="attr: { href: '#/generalTransport/' + id(), title: 'Cliquez pour ouvrir ce transport' }, text: transportNumber"></a>
        <!-- /ko -->
        <i class="icon-remove btn" data-bind="click: $root.removeLinkedTransport" style="cursor:pointer;"/>
    </span>
</div>

注意ko with: transportRelated 后跟&lt;a href="#" data-bind="text: id()"。一开始我做错了&lt;a href="#" data-bind="text: transportRelated().id()"。我们不能这样继续下去。

【问题讨论】:

  • initialValues 初始化器周围的括号真的存在吗?那些看起来是多余的。
  • 什么意思?对不起,我没听懂你。父母,你的意思是完整的实体?多余的?
  • 不,initialValues = 之后的括号,花括号周围的括号。你只需要花括号来声明一个对象字面量。
  • 好的,但这不是问题的根源。
  • 不,这无关紧要。我只是在评论 =)

标签: entity-framework knockout.js breeze durandal


【解决方案1】:

更新答案

简而言之:相关的传输实体没有出现,因为它不在缓存中。

先生。 B 拥有相关实体的 ID,并在创建新的传输链路实体时使用该 ID。但是那个 id 引用了一个不在缓存中的实体。因此,相关传输实体的导航属性返回... null。

Breeze 导航属性不会延迟加载(就像 EF 等服务器端 ORM 可能会做的那样)。您必须确保引用的实体在缓存中。

这是一个设计选择,而不是遗漏。根据我们的经验,延迟加载会导致误用,从而导致归咎于框架的性能问题。我们决定绕过这个特殊的麻烦.. 至少现在是这样。

有关更多信息,请参阅 cmets。

也许同样重要……看看我们是如何诊断问题的。在那里学到了很好的教训。

原来的“错误”答案

[这个答案原来是“错误的”,但它导致了“正确”的答案。保持连续性。]

EF 如何处理您的 LinkedTransport 实体?看起来它缺乏自己的数据属性;它只有相关实体的外键。难道是EF把LinkedTransport看作是多对多关联的联结表。

您可能知道,Breeze 不(目前......并且不会很快)支持多对多。如果你给这个表一个数据属性会发生什么……甚至是一个虚拟的数据属性,比如布尔值?这将迫使 EF 将其视为自己的实体类型......使用复合键。 Northwind 中的 OrderDetail 具有相同的结构:复合键(订单、产品)和小负载(数量、价格)。

可能还有另一种方法可以告诉 EF 在不添加虚拟属性的情况下不要将其视为多对多。我只是不记得那是什么。

【讨论】:

  • 我试图在我的 LinkedTransport 表上添加一些虚拟属性,但没有任何改变:仍然是同样的问题。还是谢谢。
  • 我强烈怀疑您有 EF 配置问题,而不是 Breeze 问题。正如我所说,Northwind OrderDetail 实体与您尝试创建的类型具有相同的基本结构。我建议您确保在服务器上获得预期的结果,然后通过网络获得。然后我会看看元数据对这个实体的描述。
  • 感谢您的问题更新,看来问题出在客户端。当您在添加linkedTransport 后立即设置断点并检查transport.linkedTransports() 的值时,是否存在新实体?如果是这样,可能会有一个事件计时竞争条件......我可以提出建议。
  • 我更新了我的问题(更新 2)以在添加 linkedTransports 后立即显示值。我希望这会有所帮助。
  • 您是否也可以确认 id=5 的传输也已经在缓存中? Breeze 不会进行延迟加载。我意识到您的扩展将检索到相关的传输......在查询时已知。但在这种情况下,您正在创建一个新链接。如果该新链接引用了不在缓存中的相关传输……微风客户端不会自动获取它。如果(如我所愿),transport-with-id-5 不在缓存中,这就解释了为什么它会在您稍后再次发出查询时出现。
猜你喜欢
  • 2019-09-04
  • 1970-01-01
  • 1970-01-01
  • 2013-09-16
  • 2019-03-09
  • 2013-11-25
  • 1970-01-01
  • 2019-10-03
  • 1970-01-01
相关资源
最近更新 更多