如何在BreezeController中调用SaveChanges()?

Bla*_*ise 2 asp.net-mvc-4 asp.net-web-api knockout.js breeze

似乎所有现有的breezejs示例都是将实体模型传递给BreezeController.

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

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

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

[HttpGet]
    public IQueryable<Item> Items() {
        return _contextProvider.Context.Items;
    }
Run Code Online (Sandbox Code Playgroud)

构建视图模型是客户端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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

    [HttpPost]
    public SaveResult SaveChanges(JObject saveBundle) {
        return _contextProvider.SaveChanges(saveBundle);
    }
Run Code Online (Sandbox Code Playgroud)

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

  1. 我只能createEntitysaveChanges?我只有一个空表格来填写并提交.当然不需要items在客户端构建整个数组.

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


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

War*_*ard 5

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

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

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

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

你必须在服务器上通过查询完全控制,顺便说一句,是否Item还是ItemViewModel.您不必为这两者公开开放式查询.您似乎知道凭借您的第二个示例查询.

命令方面.

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

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

你说:" 我能不能createEntitysaveChanges "

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

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

我不知道你的意思是"输入视图模型".微风EntityManager跟踪实体.如果您的"输入视图模型"是一个实体,EntityManager它将跟踪它.如果它已经改变并且你打电话saveChanges,经理将把它发送到控制器的SaveChanges方法.

您拥有控制器SaveChanges方法的实现.你可以做任何你想要的东西,JObject它只是变更集数据的JSON.NET表示.我认为你将从ContextProvider将该对象解析为的工作中受益SaveMap.阅读有关自定义EFContextProvider主题.大多数人认为这提供了在将这些数据传递到数据访问层之前验证和操作客户端更改集数据所需的内容......无论是EF还是其他内容.

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