如何在BreezeController中调用SaveChanges()?

时间:2013-03-07 20:34:43

标签: asp.net-mvc-4 knockout.js asp.net-web-api breeze

似乎所有现有的breezejs示例都是在BreezeController之间传递实体模型。

但几乎所有我们构建的页面都使用某种形式的视图模型。在我们没有BreezeJs的日子里,我们从存储库中检索数据(域模型)以填充(使用AutoMapper或手动)视图模型,该模型仅包含该视图的必要数据。 WebAPI仅将视图模型数据发送到浏览器,我们可以在其中填充客户端视图模型(通常是knockout可观察的)。

保存数据时,我们从<form>收集数据以填充输入视图模型,仅将该数据发送到服务器,其中输入视图模型中的数据映射到域模型。通过在存储库中的SaveChanges()实体上调用DbContext来保存更新。

现在,BreezeJs将通过创建EFContextProvider来接管所有存储库代码。我见过的例子通常会检索域模型数据,然后将其全部传递给客户端。

[HttpGet]
    public IQueryable<Item> Items() {
        return _contextProvider.Context.Items;
    }

构建视图模型是客户端javascript的工作。

当然,我们可以在服务器端构建视图模型:

[HttpGet]
public List<ItemViewModel> Items() {
    var items = _contextProvider.Context.Items
                  .Include("RelatedEntity")
                  .ToList();
    var model = new List<ItemViewModel>();
    .... some code to build model from items ....
    return model;
}

好处是通过网络传输的数据更少,我们可以在服务器端进行许多操作。但我不知道修改这个BreezeController是否是一个好习惯。但至少,它会返回列出所有项目所需的数据。

当我尝试POST数据时,真正的麻烦来了。

在我发现的BreezeJs示例中,他们使用ko.observableArray()来存储所有域模型数据,比方说vm.items。然后,新记录newItemmanager.createEntity构建到域模型中。验证数据item.entityAspect.validateEntity()后,newItem被推入vm.items并调用manager.saveChanges(),以某种方式调用BreezeController上的SaveChanges()

    [HttpPost]
    public SaveResult SaveChanges(JObject saveBundle) {
        return _contextProvider.SaveChanges(saveBundle);
    }

我发现有太多东西被接管了! (如果你不同意,请嘲笑我。)我的问题是:

  1. 我可以createEntity然后saveChanges吗? 我只有一个空表格来填写并提交。当然不需要在客户端构建整个items数组。

  2. 我可以将输入视图模型作为JObject传递,并在调用_contextProvider.SaveChanges()之前进行一些服务器端处理吗?


  3. 事实证明这是一个超长的帖子。感谢您阅读全文。真的很感激!

1 个答案:

答案 0 :(得分:5)

好问题。不幸的是,我们的演示代码似乎掩盖了Breeze在客户端和服务器上的真实功能。微风不会受到你恐惧的束缚。

我不想重复文档中的所有内容。我们确实谈到了这些问题。我们需要更多的例子来确定。

您正在描述CQRS设计。我认为它使大多数应用程序过于复杂。但这是你的特权。

如果您想发送ItemViewModel而不是Item,则可以。如果您希望将其视为Breeze客户端上的实体 - 让EntityManager将其转换为KO observable并在缓存中进行管理,更改跟踪,验证它 - 您将必须提供元数据它...在服务器或客户端上。对于Breeze来说这是真的......以及你可以命名的其他系统(Ember,Backbone等)。很快,我们将更容易在服务器上为任意CLR模型创建元数据;这可能有所帮助。

您可以完全控制服务器上的查询,无论是Item还是ItemViewModel。您不必为这两者公开开放式查询。你似乎知道你的第二个例子查询。

转到命令端。

您写道:“ [示例]使用ko.observableArray()来存储所有域模型数据,比方说vm.items

这不完全正确。您在示例中看到的items数组存在于 presentation 中。 items数组不存储Breeze透视图中的任何内容。实际上,在查询之后,查询响应中返回的实体(如果它们是实体)已经在管理器的缓存中,无论您对查询结果如何处理,无论是将它们放在数组中还是将它们丢弃。 在经理跟踪实体时,数组不起任何作用

您写道:“我可以createEntity然后saveChanges吗?

当然! EntityManager.createEntity方法将新实体放入缓存中。同样,您看到它被推入items数组的原因是为了呈现给用户。该数组与经理将节省的费用无关。

您写道:“我可以传递输入视图模型...并在调用_contextProvider.SaveChanges()之前进行一些服务器端处理吗?

我不知道“输入视图模型”是什么意思。 Breeze EntityManager跟踪实体。如果您的“输入视图模型”是一个实体,EntityManager将跟踪它。如果它已更改并且您致电saveChanges,则经理会将其发送到控制器的SaveChanges方法。

您拥有控制器的SaveChanges方法的实现。您可以使用JObject执行任何操作,这只是更改集数据的JSON.NET表示。我认为您将从ContextProvider将该对象解析为SaveMap的工作中受益。阅读topic on Customizing the EFContextProvider。大多数人认为这提供了在将这些数据传递到数据访问层之前验证和操作客户端更改集数据所需的内容......无论是EF还是其他内容。

如果您想创建自己的自定义DTO以POST到您自己的自定义控制器方法......请继续。不要打电话给EntityManager.saveChanges。调用EntityManager.getChanges()并将更改实体数组操作到您的DTO中。你会手工做所有事情。但是你可以。就个人而言,我有更好的事情要做。