Источники данных Sproutcore и модельные отношения - PullRequest
1 голос
/ 28 июня 2011

В настоящее время у меня есть настройка приложения Sproutcore со следующими отношениями на моих моделях:

App.Client = SC.Record.extend({
    name: SC.Record.attr(String),
    brands: SC.Record.toMany('App.Brand', {isMaster: YES, inverse: 'client'})
});

App.Brand = SC.Record.extend({
    name: SC.Record.attr(String),
    client: SC.Record.toOne('App.Client, {isMaster: NO, inverse: 'brands'})
});

Когда я работал с приборами, мой прибор для клиента выглядел так:

{
    guid: 1,
    name: 'My client',
    brands: [1, 2]
}

А мой крепеж для бренда выглядел так:

{
    guid: 1,
    name: 'My brand',
    client: 1
}

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

  1. Должны ли данные, возвращаемые с сервера, точно соответствовать формату файла фикстур? Таким образом, клиенты всегда должны содержать свойство бренда, содержащее массив идентификаторов бренда? И наоборот.

  2. Если у меня есть представление списка источников, в котором отображаются клиенты с марками, сгруппированными под ними. Как бы я мог загрузить эти данные для исходного представления с моим источником данных? Должен ли я позвонить на сервер, чтобы получить все клиенты, а затем выполнить звонок, чтобы получить все бренды?

Спасибо

Mark

1 Ответ

2 голосов
/ 28 июня 2011

json, который вы вернете, будет в основном отражать приборы. У меня недавно был почти такой же вопрос, как и у вас, поэтому я создал бэкэнд в Grails и внешний интерфейс в SC, просто чтобы изучить магазин и источники данных. Мои модели:

Scds.Project = SC.Record.extend(
    /** @scope Scds.Project.prototype */ {
      primaryKey: 'id',
      name: SC.Record.attr(String),
      tasks: SC.Record.toMany("Scds.Task", {
            isMaster: YES,
            inverse: 'project'
          })
    });


Scds.Task = SC.Record.extend(
    /** @scope Scds.Task.prototype */ {

      name: SC.Record.attr(String),
      project: SC.Record.toOne("Scds.Project", {
            isMaster: NO
          })

    });

JSON, возвращенный для проектов:

[{"id":1,"name":"Project 1","tasks":[1,2,3,4,5]},{"id":2,"name":"Project 2","tasks":[6,7,8]}]

и json, возвращаемый для задач, когда я выбираю проект, равен

{"id":1,"name":"task 1"}

очевидно, это json только для 1 задачи. Если вы посмотрите на проекты json, вы увидите, что я поместил массив «tasks» с идентификаторами в нем - вот как внутренняя часть знает, какие задачи получить. поэтому, чтобы ответить на ваш первый вопрос, вам не нужен идентификатор от потомка к родителю, вам нужно, чтобы родитель загружался со всеми потомками, поэтому json не совсем точно соответствует осветителям.

Теперь, это немного сложно. Когда я загружаю приложение, я делаю запрос, чтобы получить все проекты. Хранилище вызывает метод fetch для источника данных. Вот моя реализация.

Scds.PROJECTS_QUERY = SC.Query.local(Scds.Project);
var projects = Scds.store.find(Scds.PROJECTS_QUERY);
...


fetch: function(store, query) {
        console.log('fetch called');

        if (query === Scds.PROJECTS_QUERY) {
          console.log('fetch projects');
          SC.Request.getUrl('scds/project/list').json().
              notify(this, '_projectsLoaded', store, query).
              send();

        } else if (query === Scds.TASKS_QUERY) {
          console.log('tasks query');
        }

        return YES; // return YES if you handled the query
      },

      _projectsLoaded: function(response, store, query) {
        console.log('projects loaded....');

        if (SC.ok(response)) {
          var recordType = query.get('recordType'),
              records = response.get('body');

          store.loadRecords(recordType, records);
          store.dataSourceDidFetchQuery(query);

          Scds.Statechart.sendEvent('projectsLoaded')
        } else {
          console.log('oops...error loading projects');
          // Tell the store that your server returned an error
          store.dataSourceDidErrorQuery(query, response);
        }
      }

Это получит проекты, но не задачи. Sproutcore знает, что как только я получаю доступ к массиву задач в проекте, он должен получить их. То, что он делает, называется retrieveRecords в источнике данных. Этот метод в свою очередь вызывает retrieveRecord для каждого идентификатора в массиве задач. Мой метод retrieveRecord выглядит как

retrieveRecord: function(store, storeKey) {
        var id = Scds.store.idFor(storeKey);
        console.log('retrieveRecord called with [storeKey, id] [%@, %@]'.fmt(storeKey, id));

        SC.Request.getUrl('scds/task/get/%@'.fmt(id)).json().
            notify(this, "_didRetrieveRecord", store, storeKey).
            send();

        return YES;
      },

      _didRetrieveRecord: function(response, store, storeKey) {
        if (SC.ok(response)) {
          console.log('succesfully loaded task %@'.fmt(response.get('body')));
          var dataHash = response.get('body');
          store.dataSourceDidComplete(storeKey, dataHash);

        } ...
      },

Обратите внимание, что вы должны использовать sc-gen для генерации вашего источника данных, потому что он предоставляет довольно хорошо очищенную заглушку, которая направляет вас к методам, которые вам нужно реализовать. Он не обеспечивает реализацию retrieveMethods, но вы можете предоставить свою собственную, если не хотите делать один запрос для каждой дочерней записи, которую вы загружаете.

Обратите внимание, что у вас всегда есть варианты. Если бы я захотел, я мог бы создать запрос «Задачи» и загрузить все данные о задачах заранее, так что мне не нужно было бы переходить на мой сервер, когда я щелкал проект. Так что в ответ на ваш второй вопрос, это зависит. Вы можете либо загружать бренды, когда нажимаете на клиента, либо загружать все данные заранее, что, вероятно, будет хорошей идеей, если данных не так много.

...