Как управлять новыми объектами Breeze, которые являются совокупными корнями?

У меня есть модель домена, в которой есть клиент, который, в свою очередь, имеет 1 адрес (1: 1) и 1 или более телефонных номеров (1: M). У клиента есть PK, предоставленный пользователем (строка), в то время как Address и Phone используют столбец идентификаторов (сгенерированный сервером).

Я изо всех сил пытаюсь понять, как управлять созданием объекта 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 ---

и мой "/services/datacontext.js":

// -- 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 ---

Мои вопросы следующие:

  • После того, как я создам клиента, мне нужно создать адрес и список телефонов и добавить их в сущность клиента, прежде чем сделать его наблюдаемым KO? Или это делается автоматически методом createEntity()?
  • Как создать клиента, но без указания идентификатора? Если я устанавливаю для ключа значение null или '', Breeze жалуется ("Ошибка: невозможно прикрепить объект к EntityManager без предварительной установки его ключа или установки его свойства entityType 'AutoGeneratedKeyType' в значение, отличное от 'None'"). Однако, если я генерирую временный ключ (используя либо breeze.core.getUuid(), либо что-то еще), то он отображается в моем поле формы Id, и я действительно хочу, чтобы конечный пользователь указал его... У меня есть прибегнуть к расширению объекта дополнительным полем, а затем выполнить замену и проверку перед сохранением (мне эта идея вообще не нравится)? Есть ли способ лучше?
  • Чтобы включить/отключить кнопки в моей форме, я отслеживаю, есть ли изменения в EntityManager. Но каждый раз, когда сущность создается, она автоматически находится в состоянии «добавлено», поэтому hasChanges имеет значение true. Я хочу, чтобы изменения принимались только в том случае, если пользователь редактирует форму (и, следовательно, вносит изменения в базовый объект). Как лучше всего подойти к этому?

Кстати, я видел эту рекомендацию зарегистрировать собственный конструктор для объекта (я уже реализовал его, но до сих пор не понимаю, как чтобы пользователь мог указать свой собственный идентификатор и пометить объект как измененный только тогда, когда пользователь редактирует его...)


person zam6ak    schedule 29.05.2013    source источник


Ответы (2)


Я понимаю, что это было какое-то время, но вот мои мысли (на случай, если кто-нибудь заглянет).

  1. Если вы используете entityManager для создания своего клиента и все правильно указано в метаданных, вы можете просто создать клиента и добавить номера телефонов/адреса по мере необходимости. Breeze автоматически делает свойства объекта наблюдаемыми (если указано правильно и если ветер знает, что используется KO)

  2. Если вы можете делать это только так, как говорите, то вы застряли. В идеале у вас должен быть введенный пользователем идентификатор, который НЕ является ключом (хотя вы все равно можете сделать его уникальным) и ключ, сгенерированный базой данных, которым Breeze будет управлять за кулисами (назначая отрицательный ключ, пока он не будет сохранен в хранилище данных, а затем обновление ключа и всех связанных ключей без вашего участия).

  3. если вы используете второй подход для ответа 2, ваши кнопки можно легко включать и отключать с помощью привязки данных ko. При создании объекта сохраните его значение в модели представления (custSource). Затем вы можете добавить к кнопке сохранения data-bind="disable: custSource == Customer(), enable: custSource != Customer()". (Возможно, вам придется поиграть с синтаксисом — я еще не тестировал эту часть)

Я не думаю, что вам нужен собственный конструктор, если вы не делаете что-то отличное от того, что я понимаю.

PS. вы должны знать, что я считаю, что Breeze хочет, чтобы Knockout определялся как «ko», в то время как Durandal определенно ожидает, что это будет «knockout», поэтому вам, вероятно, понадобится свойство «map» в вашем require.config

person Beartums    schedule 25.11.2014

Я думаю, что вы могли бы решить некоторые из ваших проблем, применив несколько иной подход к созданию вашей сущности. Вот ваш текущий подход:

  1. Создать сущность клиента
  2. Пользователь изменяет этот объект
  3. Сохраните изменения

Вместо этого попробуйте следующее:

  1. Пользователь вводит информацию о клиенте
  2. Создайте и сохраните сущность клиента

Я понимаю, что на самом деле это не отвечает на ваши вопросы, но я обнаружил, что второй подход намного проще реализовать. Просто попросите пользователя ввести всю информацию, необходимую для создания клиента, а затем предоставить эти значения в создать объект.

customeradd.js

// -- 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 ---

/services/datacontext.js

// -- 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 ---
person blachniet    schedule 05.06.2013
comment
Ваша рекомендация, безусловно, сделает ее более управляемой, но это также будет означать, что для каждой формы у меня будут поля viemodel, которые будут почти 1: 1 со свойствами сущности... Представьте себе сущность клиента с 20-30 свойствами, а затем иметь viewmodel с таким количеством ко наблюдаемых... Теперь умножьте это на 40-50 сущностей в модели предметной области... Это много повторений, не так ли? - person zam6ak; 05.06.2013
comment
Да, это было бы много повторений, и это было бы абсолютно отстойно... Я посмотрю, смогу ли я придумать что-нибудь получше. - person blachniet; 06.06.2013
comment
ознакомьтесь также с этим q (stackoverflow.com/q/16928767/481904), в котором есть некоторые комментарии @ Ward (один парней из Breeze) :) - Моя цель - избежать повторения формы привязки ‹-> сущности Breeze, имея при этом пользовательский опыт, который имеет смысл (см. мой комментарий относительно значений по умолчанию для сущностей Breeze) - person zam6ak; 06.06.2013