Asp.net web api 如何管理作为聚合根的新Breeze实体?

Asp.net web api 如何管理作为聚合根的新Breeze实体?,asp.net-web-api,breeze,single-page-application,durandal,Asp.net Web Api,Breeze,Single Page Application,Durandal,我有一个域模型,它有一个客户,客户又有一个地址(1:1)和一个或多个电话号码(1:M)。 客户有用户提供的PK(字符串),而地址和电话使用标识列(服务器生成) 我正在努力理解如何为“添加新客户”屏幕管理Breeze实体创建。 屏幕上的表单允许用户输入客户、地址和电话数据 我使用的是Durandal和Knockout,因此我的“customeradd.js”视图模型如下所示: // -- snip --- var customer = ko.observable(), ha

我有一个域模型,它有一个客户,客户又有一个地址(1:1)和一个或多个电话号码(1:M)。 客户有用户提供的PK(字符串),而地址和电话使用标识列(服务器生成)

我正在努力理解如何为“添加新客户”屏幕管理Breeze实体创建。 屏幕上的表单允许用户输入客户、地址和电话数据

我使用的是Durandal和Knockout,因此我的“customeradd.js”视图模型如下所示:

// -- snip ---
    var customer = ko.observable(),
        hasChanges = ko.computed(function () {
            return datacontext.hasChanges();
        });

    var vm = {
        hasChanges: hasChanges,
        customer: customer,
        activate: activate
    };

    return vm;

    function activate() {
        customer(datacontext.createCustomer());
    }
// -- snip ---
和my“/services/datacontext.js”:

我的问题如下:

  • 一旦我创建了一个客户,我是否需要创建地址和电话列表,并将其添加到客户实体中,然后才能使其成为可观察的对象?或者这是通过createEntity()方法自动完成的
  • 如何创建客户而不必指定Id?如果我将键设置为null或“”,Breeze会抱怨(“错误:在未首先设置其键或未将其entityType“AutoGeneratedKeyType”属性设置为“None”以外的其他属性的情况下,无法将对象附加到EntityManager”)。但是,如果我生成临时密钥(使用breeze.core.getUuid()或其他方法),那么它将显示在我的Id表单字段中,我真的希望最终用户指定它……我是否必须使用额外字段扩展实体,然后在保存之前进行交换和验证(我一点都不喜欢这个想法)?有更好的办法吗
  • 为了启用/禁用表单上的按钮,我正在跟踪EntityManager中是否有更改。但每次创建实体时,它都会自动处于“添加”状态,所以hasChanges是真的。我想要的是,只有在用户编辑表单(并因此对参考底图图元进行更改)时,才能选择更改。最好的方法是什么

顺便说一句,我已经看到为实体注册自定义构造函数(我已经实现了它,但我仍然不清楚如何让用户提供自己的id,以及如何仅在用户编辑实体时将其标记为已修改…)

我想您可以通过采用稍微不同的方法创建实体来解决一些问题。以下是您目前的做法:

  • 创建客户实体
  • 用户修改该实体
  • 保存更改
  • 相反,请尝试以下方法:

  • 用户输入客户信息
  • 创建并保存客户实体
  • 我意识到这并不能真正回答您的问题,但我发现第二种方法更容易实现。只需让用户输入创建客户所需的所有信息,然后将这些值提供给

    customeradd.js

    /服务/datacontext.js


    我意识到这已经有一段时间了,但以下是我的想法(以防有人来看)

  • 如果使用entityManager创建customerl,并且元数据中的所有内容都已正确指定,则只需创建客户并根据需要添加电话号码/地址即可。Breeze自动使实体的属性可见(如果正确指定并且Breeze知道正在使用KO)

  • 如果你只能按你说的方式去做,那么你就被卡住了。理想情况下,您将拥有一个用户输入的ID,它不是密钥(尽管您仍然可以强制它是唯一的)和一个数据库生成的密钥,Breeze将在后台管理该密钥(分配一个负密钥,直到将其保存到数据存储中,然后更新密钥和所有相关密钥,而无需您进行任何输入)

  • 如果回答2使用第二种方法,则可以使用ko数据绑定轻松启用和禁用按钮。创建实体时,将其值保存到viewmodel(custSource)。然后,您可以将数据绑定=“disable:custSource==Customer(),enable:custSource!=Customer()”添加到保存按钮。(您可能需要尝试一下语法——我还没有测试该部分)

  • 我不认为你需要一个自定义构造函数,除非你正在做一些不同于我理解的事情


    另外,你应该知道,我相信Breeze希望淘汰赛被定义为“ko”,而Durandal肯定希望它是“淘汰赛”,因此,您可能需要require.config中的“map”属性,您的建议肯定会使其更易于管理,但这也意味着对于每个表单,我都会有一个viemodel字段,该字段与实体属性几乎是1:1……想象一下,客户实体具有20-30个属性,然后必须具有一个viemodel属性许多ko观测值…现在在一个领域模型中乘以40-50个实体…这是一个很大的重复,你不认为吗?是的,那将是一个很大的重复,它绝对会很糟糕。。。我会看看我是否能想出一些更好的东西。也看看这个q(),它有@Ward(Breeze“家伙”之一)的一些评论:)-我的目标是避免重复绑定形式Breeze实体,同时拥有有意义的用户体验(参见我关于Breeze实体默认值的评论)
    // -- snip ---
        breeze.NamingConvention.camelCase.setAsDefault();
    
        var manager = new breeze.EntityManager(config.remoteServiceName);
        var hasChanges = ko.observable(false);
    
        manager.hasChangesChanged.subscribe(function (eventArgs) {
            hasChanges(eventArgs.hasChanges);
        });
    
        function createVehicle() {
            return manager.createEntity("Customer");
        }
    // -- snip ---
    
    // -- snip ---
        var vm = {
            customerId: ko.observable(),
            address: ko.observable(""),
            phoneNumbers: ko.observableArray([]),
    
            submit: submit
        };
    
        return vm;
    
        function submit() {
            datacontext.createCustomer(
                vm.customerId(), 
                vm.address(),
                vm.phoneNumbers());
        }
    // -- snip ---
    
    // -- snip ---
        /**
         * Creates a new customer.
         * @param {int} id - The customer's id number.
         * @param {string} address - The customer's address.
         * @param {string[]} phoneNumbers - An array of the customer's phone numbers.
         */
        function createCustomer(id, address, phoneNumbers) {
            return manager.createEntity("Customer",
            {
                id: id,
                address: address,
                phoneNumber: phoneNumbers
            });
        }
    // -- snip ---