Много-ко-многим реляционная поддержка в JSData

есть ли способ определить отношение "многие ко многим" в JSData?

например, у меня есть 3 таблицы:

сущность entityFile файл

в " сущности "я хочу иметь отношение под названием" Файлы", которое выполняет соединение через entityFile.

1 ответов


хороший вопрос. Типичные отношения "многие ко многим" -это просто два отношения "один ко многим":

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

помещения:

A помощью методов hasmany B

B помощью методов hasmany A

1

информация о взаимоотношениях хранится в экземплярах A.

в этом сценарии, как только у вас есть экземпляр A вы можете найти Его, связанного примеры B, потому что идентификаторы, связанные B экземпляры хранятся на A. Это также означает, что если у вас есть только экземпляр B единственный способ найдите все экземпляры A что B экземпляр относится к будет поиск всех экземпляров A для тех, чей b_ids поле содержит id на B экземпляра.

пример

var Player = store.defineResource({
  name: 'player',
  relations: {
    hasMany: {
      team: {
        // JSData will setup a "teams" property accessor on
        // instances of player which searches the store for
        // that player's teams
        localField: 'teams',
        localKeys: 'team_ids'
      }
    }
  }
})

var Team = store.defineResource({
  name: 'team',
  relations: {
    hasMany: {
      player: {
        localField: 'players',
        // Since relationship information is stored
        // on the player, in order to retrieve a
        // team's players we have to do a O(n^2)
        // search through all the player instances
        foreignKeys: 'team_ids'
      }
    }
  }
})

теперь давайте посмотрим его в действии:

var player = Player.inject({
  id: 1,
  team_ids: [3, 4]
})

// The player's teams aren't in the store yet
player.teams // [ ]

var player2 = Player.inject({
  id: 2,
  team_ids: [4, 5],
  teams: [
    {
      id: 4
    },
    {
      id: 5
    }
  ]
})

// See the property accessor in action
player2.teams // [{ id: 4 }, { id: 5 }]

// One of player one's teams is in the store now
player.teams // [{ id: 4 }]

// Access the relation from the reverse direction
var team4 = Team.get(4) // { id: 4 }

// The property accessor makes a O(n^2) search of the store because
// the relationship information isn't stored on the team
team4.players // [{ id: 1, team_ids: [3, 4] }, { id: 2, team_ids: [4, 5] }]

давайте загрузим отношение из слоя персистентности:

// To get an authoritative list of player one's 
// teams we ask our persistence layer.
// Using the HTTP adapter, this might make a request like this:
// GET /team?where={"id":{"in":[3,4]}} (this would be url encoded)
//
// This method call makes this call internally:
// Team.findAll({ where: { id: { 'in': player.team_ids } } })
player.DSLoadRelations(['team']).then(function (player) {

  // The adapter responded with an array of teams, which
  // got injected into the datastore.

  // The property accessor picks up the newly injected team3
  player.teams // [{ id: 3 }, { id: 4 }]

  var team3 = Team.get(3)

  // Retrieve all of team3's players.
  // Using the HTTP adapter, this might make a request like this:
  // // GET /player?where={"team_ids":{"contains":3}} (this would be url encoded)
  //
  // This method call makes this call internally:
  // Player.findAll({ where: { team_ids: { 'contains': team3.id } } })
  return team3.DSLoadRelations(['player'])
})

если вы используете http-адаптер, то ваш сервер должен проанализировать querystring и ответить с правильными данными. Если вы используете какой-либо из затем другие адаптеры адаптер уже знает, как вернуть нужные данные. Использование JSData на интерфейсе и backend просто делает это слишком легко.

2

информация о взаимоотношениях хранится в экземплярах B.

это как раз обратное 1.

3

"A помощью методов hasmany B " информация о взаимоотношениях хранится в экземплярах A, и "B помощью методов hasmany A " информация о взаимоотношениях хранится в экземплярах B.

это просто 1 за исключением того, что теперь он работает в обоих направлениях.

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

4

информация о взаимоотношениях хранится в сводной (соединительной) таблице.

A помощью методов hasmany C и C принадлежит A, где фактическое отношение информация хранится в C.

B помощью методов hasmany C и C принадлежит B, где фактическое отношение информация хранится в C.

пример:

var Player = store.defineResource({
  name: 'player',
  relations: {
    hasMany: {
      membership: {
        localField: 'memberships',
        // relationship information is stored on the membership
        foreignKey: 'player_id'
      }
    }
  }
})

var Team = store.defineResource({
  name: 'team',
  relations: {
    hasMany: {
      membership: {
        localField: 'memberships',
        // relationship information is stored on the membership
        foreignKey: 'team_id'
      }
    }
  }
})

и ось Ресурс:

var Membership = store.defineResource({
  name: 'membership',
  relations: {
    belongsTo: {
      player: {
        localField: 'player',
        // relationship information is stored on the membership
        localKey: 'player_id'
      },
      team: {
        localField: 'team',
        // relationship information is stored on the membership
        localKey: 'team_id'
      }
    }
  }
})

теперь давайте посмотрим его в действии:

var player = Player.inject({ id: 1 })
var player2 = Player.inject({ id: 2 })
var team3 = Team.inject({ id: 3 })
var team4 = Team.inject({ id: 4 })
var team4 = Team.inject({ id: 5 })

player.memberships // [ ]
player2.memberships // [ ]
team3.memberships // [ ]
team4.memberships // [ ]
team5.memberships // [ ]

обратите внимание, что на данный момент мы еще не можем получить доступ к любым отношениям

// The relationships stored in our pivot table
var memberships = Membership.inject([
  {
    id: 997,
    player_id: 1,
    // player one is on team three
    team_id: 3
  },
  {
    id: 998,
    player_id: 1,
    // player one is also on team four
    team_id: 4
  },
  {
    id: 999,
    player_id: 2,
    // team four also has player 2
    team_id: 4
  },
  {
    id: 1000,
    player_id: 2,
    // player 2 is also on team 5
    team_id: 5
  }
])

теперь у нас есть информация о членстве

player.memberships // [{ id: 997, ... }, { id: 998, ... }]
player2.memberships // [{ id: 998, ... }, { id: 999, ... }]
team3.memberships // [{ id: 997, ... }]
team4.memberships // [{ id: 998, ... }, { id: 999, ... }]
team5.memberships // [{ id: 1000, ... }]

теперь немного неуклюже отправлять данные сводной таблицы на ваш интерфейс и требуется ваш JavaScript для сортировки отношений. Ради этого ты бы хотел ... некоторые вспомогательные методы:

var Player = store.defineResource({
  name: 'player',
  relations: {...},
  computed: {
    teams: {
      get: function () {
        return store.filter('membership', {
          player_id: this.id
        }).map(function (membership) {
          return store.get('team', membership.team_id)
        })
      }
    }
  },
  // Instance methods
  methods: {
    getTeams: function () {
      return Player.getTeams(this.id)
    }
  }
  // Static Class Methods
  getTeams: function (id) {
    return this.loadRelations(id, ['membership']).then(function (memberships) {
      return store.findAll('team', {
        where: {
          id: {
            'in': memberships.map(function (membership) {
              return membership.team_id
            })
          }
        }
      })
    })
  }
})

я позволю вам выяснить аналогичные методы для командный ресурс.

если вы не хотите идти на неприятности вспомогательных методов, то вы можете просто реализуйте их на бэкэнде, чтобы сделать вашу сводную таблицу невидимой для сделайте ваши отношения "многие ко многим" более похожими на Вариант 1, 2 или 3.

Полезные ссылки