在我的foreach淘汰循环中,新添加的实体未正确显示

时间:2013-08-22 15:29:59

标签: entity-framework knockout.js breeze durandal

我在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

的可观察对象中
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的属性。但是,如果我saveChanges并重新加载我的页面,那么我可以读取目标linkedTransport的属性。

当我说'targetted linkedTransport'时,我指的是我的TransportRelatedId(&gt;&gt;&gt; public virtual Transport TransportRelated)引用的传输。

因此,如果我立即将linkedTransport #123 添加到传输#456 那么(无需重新加载页面)我无法显示该属性的Description属性#123。

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

希望我很清楚。


更新2

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

enter image description here

  • transport()。linkedTransports()[0] .transport()&gt;&gt;属性在哪里
  • transport()。linkedTransports()[0] .transportId()&gt;&gt; 1
  • transport()。linkedTransports()[0] .transportNumber&gt;&gt; '123456'(“虚拟”属性,没有帮助)
  • transport()。linkedTransports()[0] .transportRelated()&gt;&gt;空
  • transport()。linkedTransports()[0] .transportRelatedId()&gt;&gt; 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后跟<a href="#" data-bind="text: id()"。起初我做错了<a href="#" data-bind="text: transportRelated().id()"。我们不能这样做。

1 个答案:

答案 0 :(得分:0)

更新答案

缺点:相关的传输实体没有显示,因为它不在缓存中。

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

Breeze导航属性不会延迟加载(作为服务器端的ORM,如EF可能会这样做)。您必须确保引用的实体位于缓存中。

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

有关详细信息,请参阅评论。

也许同样重要......看看我们如何诊断出这个问题。在那里学到了很好的经验教训。

原始“错误”答案

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

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

正如你可能知道的那样,Breeze不会(但不会很快)支持很多人。如果你给这个表一个数据属性...甚至一个虚拟数据属性,如布尔值会发生什么?这将迫使EF将其视为自己的实体类型......使用复合键。 Northwind的OrderDetail具有相同的结构:复合键(订单,产品)和小工资(数量,价格)。

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