【问题标题】:Deleting element from an observableArray从 observableArray 中删除元素
【发布时间】:2013-09-14 20:17:00
【问题描述】:

我有一个 ASP.NET MVC 应用程序,它在客户端使用了 durandal、knockout.js 和微风。我有一个反复遇到的问题,但我在任何地方都没有找到任何提及。不知道我是否让自己陷入了一个独特的境地,或者我只是没有找到正确的方法。

我需要知道如何从 observableArray 中删除 Breeze 实体,以便提交成功(参见下面的选项 A)并且 UI 反映更改(参见下面的选项 B)。

我有以下型号(略):

public class Donor
{
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public virtual IList<Contact> Contacts { get; set; }
}

public class Contact
{
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [ForeignKey("Donor")]
    public int? DonorId { get; set; }
    public virutal Donor Donor { get; set; }
}

我正在尝试从我的捐赠者中删除联系人。我很难在 Breeze 和 Knockout 之间获得正确的流程,因此该项目既可以从 observableArray 中删除(带有通知),也可以通过 Breeze 删除。

这是我尝试过的(javascript):

选项 A

function deleteContact(contact){
    viewModel.donor().contacts.remove(contact);
    contact.entityAspect.setDeleted();
    viewModel.uow.commit();
}

当我使用这种方法时,我从 Breeze.WebApi 收到以下错误:

Int32Converter 无法从 System.Int64 转换

我查看了堆栈,并检查了 Breeze 源代码(虽然我还没有配置解决方案来逐步完成它),错误来自 Breeze.WebApi.EFContextProvider::RestoreOriginal,它在哪里将原始属性值恢复到对象。我不知道为什么它认为我的值是 Int64,但我找不到好的解决方法,所以我尝试了...

选项 B

function deleteContact(contact){
    contact.entityAspect.setDeleted();
    viewModel.uow.commit();
}

这种方法允许我成功保存删除(因为该项目尚未手动从集合中删除,因此没有任何“原始值”)。但是,这里的问题是 setDeleted 有效地从 observableArray 中删除了该项目没有通知我的淘汰赛绑定该数组已更改。因此该项目已被删除并删除,但我的 UI 仍然显示该项目。以后尝试调用donor().contacts.remove(contact) 是徒劳的,因为 observableArray 不再有该项目。

【问题讨论】:

  • 您是否尝试在使用选项 b 后在可观察数组上调用 valueHasMutated()
  • 我没有尝试过,它确实有效,所以谢谢。继续添加答案 - 我很好奇是否有任何 IdeaBlade 人对此有想法,所以我可能会让它打开一两天,看看他们是否会加入。仍然想知道我是否是唯一得到的人该转换器错误...
  • Breeze 应该知道 KO 吗?考虑:var foo = ko.observableArray(["A"]); foo.push("B"); 这会更新数组和 DOM。 foo().push("C"); 这只会更新数组。选项 A 是正确的,但根据您的经验,选项 B 不正确。这是一个jsfiddle 示例。您可以看到值未移动到每个数组,但只有一个更新了 DOM。如果您在 applyBindings 之后添加 vm.foo.valueHasMutated();,则 DOM 会同时更新两者,这是这里发生的事情及其工作原理的简化版本。
  • @Dennis - 是的,我相信 Breeze 具有 KO 意识。当我使用 Breeze 检索我的实体时,Breeze 会在幕后对所有内容进行 KO,这意味着我的实体上的所有属性都是 observables 或 observableArrays。因此,它清楚地认识到 KO 参与其中,并使我的对象对 KO 友好。 Breeze 文档中的This topic 专门讨论了这种集成。
  • 我必须阅读 Breeze,但我无法想象他们会在对实体进行更改后让您在教程中显式调用 valueHasMutated。

标签: c# javascript knockout.js entity-framework-5 breeze


【解决方案1】:

您是否尝试在使用选项 b 后在可观察数组上调用 valueHasMutated()

这将通知订阅者 observable 已更改。

【讨论】:

    【解决方案2】:

    如果您“删除”或“分离”实体,Breeze 会自动从任何导航集合中删除该实体。所以我会尝试消除

     viewModel.donor().contacts.remove(contact);  
    

    line 并查看调用 'setDeleted' 本身是否满足您的需要。

    【讨论】:

    • 看看我上面的选项 B,它不包括显式删除实体,你会明白为什么这不起作用。
    • 对不起,我应该更仔细地阅读您的帖子。我会进行一些测试来确认这一点。如果您是对的,那么我将在下一个版本中添加此问题以进行修复。在此之前,直接调用 valueHasMutated 应该没问题。
    【解决方案3】:

    TL:DR

    切勿在 createEntity 的初始化程序中设置 FK,同时将实体推送到父级的导航属性。保留其中任何一个,但不能同时保留。

    基本原则

    在遇到类似问题并进行了大量调查后,我想提出一个替代答案。您正在试验的问题不在于您如何删除该项目,而是您如何创建该项目。

    Breeze 在管理其数据上下文方面非常有能力。它知道导航属性和外键以及如何处理它们。作为本地数据上下文的副作用,所有可观察对象也拥有这种智能。这就是您可能忽略了一些东西并最终遇到了这个问题的地方。

    追踪微风的代码

    这一切具体意味着什么?好吧,您可以使用两种方法来使用微风创建具有父实体的对象。第一个是通过在初始化程序中设置其父 id,如下所示:

    var c = manager.createEntity('contact', { 'donorId': 12, 'name': 'bob' });
    

    另一种是将实体添加到微风数据上下文中父实体的导航属性中。

    var parents = ko.observableArray();
    manager.runQuery(..., parents);
    
    var c = manager.createEntity('contact', { 'name': 'bob'});
    parents.contacts.push(c);
    

    这两种情况各有利弊。当您尝试同时执行这两种操作时会出现问题:

    var parents = ko.observableArray();
    manager.runQuery(..., parents);
    
    var c = manager.createEntity('contact', { 'donorId': 12, 'name': 'bob' });
    parents.contacts.push(c);
    

    Breeze 在处理插入时尝试优化其查询以防止 UI 闪烁。当调用 push 时,它会禁用目标 observable 上的通知,直到整个操作完成。然后,它将在内部调用valueHasMutated,这将触发 UI 刷新。问题是,调用createEntity 会干扰此机制并导致通知过早地重新初始化。然后push 将保存这个无效状态,交换并重置它,使 observable 处于无效状态。

    当您最终调用 setDeleted 时,通知仍将在 observable 上被禁用,从而阻止 UI 刷新,即使数据已正确推送到微风的数据上下文中。这只会在插入新元素后发生一次。删除元素将强制将状态更改为正确的值,并且导航属性上的所有后续删除都将触发 UI 刷新。

    看看你的两个选择

    最后,您只需使用setDeleted 即可从微风导航属性中正确删除实体。无需手动将其从 observable 中删除,实际上,这样做会将外键重置为 null,如果模型中的类型不可为空或尝试删除时出错,这可能会导致服务器上出现反序列化问题数据库中的行取决于您的主键是如何定义的。选项 B 是首选。

    【讨论】:

      猜你喜欢
      • 2014-04-03
      • 1970-01-01
      • 2012-07-12
      • 2013-06-30
      • 2013-10-23
      • 2013-02-14
      • 2018-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多