0

我做了什么

我在 donejs 中创建了一个组件,然后创建了两个超模contactemail使用以下命令:

  • donejs add component contactComponent contact-component
  • donejs add supermodel contact
  • donejs add supermodel email

有一个提供联系人和电子邮件的 API (feathers+mongodb)。每封电子邮件都有一个contactId.

该组件包含Contact模型并处理诸如保存、创建新元素、删除元素等操作。将其与.stache文件组合时,它将成功地从 API 中检索元素并相应地列出它们。

所以每个Contact人都有电子邮件。由于每个联系人都有自己的电子邮件,因此contactComponent 无法直接获取它们,而是通过 Contact元素获取它们。

这就是我的设计问题开始的地方。

到目前为止,contactComonent 创建了一个处理联系人处理方式的视图模型。联系人模型处理 API 连接。这工作正常,可扩展且干净。

但是每个联系人都需要一个新模型来加载数据(电子邮件),然后我直接使用该模型来管理与电子邮件相关的所有逻辑。这确实有效,但似乎让模型处理连接和处理复杂交互的视图模型更适合 MVVM 设计模式。

我想我不是第一个进行此类数据建模的人,我认为必须有更好的解决方案,尤其是在处理大量关系和更复杂的关系时。

我认为我目前拥有的是这样的:

contactComponent.js
├── (includes) models/contact.js
│   ├── (includes) models/email.js

这就是我正在寻找的(我可能错了)

contactComponent.js
├── (includes) models/contact.js
├── (includes / relates / references) emailComponent.js
emailComponent.js
├── (includes) models/email.js

使用过的文件

文件结构
contactComponent
├── contactComponent.js
├── contactComponent.stache
models
├── contact.js
├── email.js
联系人组件/contactComponent.js
/* contactComponent/contactComponent.js */
import Component from 'can/component/';
import Map from 'can/map/';
import 'can/map/define/';
import template from './contactComponet.stache!';
import Contact from '../models/contact.js';


export const ViewModel = Map.extend({
  define: {
    contactPromise: {
      get: function() {
        return Contact.getList({});
      }
    }
  },
  saveContact: function() {
    // do some stuff
  },
  deleteContact: function() {
    // do some stuff
  }
});

export default Component.extend({
  tag: 'contact-component',
  viewModel: ViewModel,
  template
});
contactComponent/contactComponent.stache
/* contactComponent/contactComponent.stache */
{{#if contactPromise.isResolved}}
  {{#each contactPromise.value}}
    Name: {{name}}
    {{#if emailPromise.isResolved}}
      Emails:
      {{#each emailPromise.value}}
        {{email}}
      {{/each}}
    {{/if}}
  {{/each}}
{{/if}}
模型/email.js
/* models/email.js */
import can from 'can';
import superMap from 'can-connect/can/super-map/';
import tag from 'can-connect/can/tag/';
import 'can/map/define/define';

export const Email = can.Map.extend({
  define: {},
  type: null,
  email: null,
});

Email.List = can.List.extend({
  Map: Email
}, {});

export const emailConnection = superMap({
  url: '/api/modelEmail',
  idProp: '_id',
  Map: Email,
  List: Email.List,
  name: 'email'
});

tag('email-model', emailConnection);

export default Email;

这是事情开始变得过于复杂的地方:

模型/contact.js
/* models/contact.js */
import can from 'can';
import superMap from 'can-connect/can/super-map/';
import tag from 'can-connect/can/tag/';
import 'can/map/define/define';
import Email from '../models/email.js';

export const Contact = can.Map.extend({
  define: {
    emailPromise: {
      get: function() {
        return Email.getList({ contactId: this.attr('id') });
      }
    }
  },
  name: null,
});

Contact.List = can.List.extend({
  Map: Contact
}, {});

export const contactConnection = superMap({
  url: '/api/modelContact',
  idProp: '_id',
  Map: Contact,
  List: Contact.List,
  name: 'contact'
});

tag('contact-model', contactConnection);

export default Contact;
4

1 回答 1

0

没有一种正确的方法可以回答您的问题,但让我描述一下我的工作。

通常,模型关系是在模型级别定义的。据我所知,大多数 ORM 都是这样工作的(例如 Mongoose 和 Sequelize)。我更喜欢双方都知道关系 - 例如,您的联系人模型知道它有很多电子邮件,而电子邮件模型知道它属于一个联系人。每个模型都可以独立存在 - 这意味着您在与联系人打交道时不必电子邮件,反之亦然。

然后模型可以公开用于检索相关数据的辅助方法。因此,您的 Contact 模型可以实现诸如getEmails()setEmails()addNewEmail()、之类的方法doSomethingUniqueWithEmails()。您的电子邮件模型可以使用getContact()和做同样的事情setContact()。这些方法将处理实际的数据事务(进行 AJAX 调用)——因此您可以根据自己的需要来实现该部分。例如,当您打电话时contact.setEmails([...])- 联系人模型会在所有电子邮件上设置 contactId 并为此打电话EmailModel.save()或其他事情。

最后,您的 viewModel 将根据需要使用辅助方法来处理业务。您的模型唯一关心的是关系以及如何将数据持久化到服务器。然后,您的 viewModel 将使用业务逻辑来确定如何以及何时创建、销毁数据等。

希望有帮助。

于 2017-03-22T19:29:55.570 回答