JSData中的多对多关系支持

时间:2015-10-28 17:40:44

标签: jsdata

有没有办法在JSData中定义多对多关系?

例如,我有这3个表:

实体 entityFile 文件

在“实体”上,我希望有一个名为“files”的关系,它通过entityFile进行连接。

1 个答案:

答案 0 :(得分:8)

好问题。典型的多对多关系只是两个一对多的关系:

任何实现中更重要的细节之一是:在哪里 关系信息存储?这个问题的答案决定了如何 可以访问实体的关系。让我们探讨一些选择。

前提:

A hasMany B

B hasMany A

选项1

关系信息存储在A

的实例中

在这种情况下,一旦你有一个A的实例,你就可以找到它的关联 B的实例,因为存储了关联的B实例的ID 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'])
})

让我们从持久层加载关系:

B

如果您正在使用HTTP适配器,那么它可以直接到您的服务器来解析 查询字符串并使用正确的数据进行响应。如果你正在使用任何一个 其他适配器然后适配器已经知道如何返回正确的数据。 在前端后端使用JSData只会让这很容易。

选项2

关系信息存储在A

的实例中

这只是选项1 的反面。

选项3

" B hasMany A"关系信息存储在实例B上,和 " A hasMany B"关系信息存储在foreignKeys

的实例中

这只是选项1 ,但它现在可以双向工作。

这种方法的一个优点是您可以从两者访问关系 方向,无需使用A选项。一个缺点 这种方法是当关系发生变化时必须修改数据 多个地方。

选项4

关系信息存储在数据透视(联结)表中。

C hasMany CA belongsTo C,其实际关系 信息存储在B

C hasMany CB belongsTo 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, ... }]

现在我们有会员资料

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
            })
          }
        }
      })
    })
  }
})

现在,将您的数据透视表数据发送到您的前端并且有点笨拙 要求你的JavaScript对关系进行排序。为此你想要的 一些辅助方法:

    static void InsertTextInCell(WorksheetPart worksheetPart)
    {
        Worksheet workSheet = worksheetPart.Worksheet;
        SheetData sheetData = workSheet.GetFirstChild<SheetData>();

        Cell cell = new Cell()
        {
            CellReference = "E8",
            DataType = CellValues.String,
            CellValue = new CellValue("Adding Value")
        };
        sheetData.Append(cell);
    }

我会让你弄清楚团队资源的类似方法。

如果你不想解决辅助方法的麻烦,那么你可能会 只需在后端实现它们,使您的数据透视表不可见 前端并使你的多对多关系看起来更像是选项1,2或 3。

有用的链接

相关问题