【问题标题】:Angularjs: Many-to-Many with Through RelationshipAngularjs:通过关系的多对多
【发布时间】:2015-10-30 03:53:33
【问题描述】:

在我的应用中,我有学生可以注册班级

注册记录开始和结束日期以及对哪个班级的引用。

类具有详细信息,例如类名称和描述。

学生 (1) - (N) 入学 (1) - (1) 班级

因此

学生 (1) - (N) 班

这就是我希望对象看起来的样子。

{
  "studentId": 1,
  "name": "Henrietta",
  "enrolledClasses": [
    {
      "enrollmentId": 12,
      "startDate": "2015-08-06T17:43:14.000Z",
      "endDate": null,
      "class": 
        { 
          "classId": 15,
          "name": "Algebra",
          "description": "..."
        }
    },
      "enrollmentId": 13,
      "startDate": "2015-08-06T17:44:14.000Z",
      "endDate": null,
      "class": 
        {
          "classId": 29,
          "name": "Physics",
          "description": "..."
        }
    }
}

但是我的 RESTful API 不能(轻松)输出关系的完整嵌套结构,因为它的 ORM 不能通过关系进行多对多。所以我得到了学生和他们的多次注册,但只是每个班级的参考,而不是细节。而且我需要显示详细信息,而不仅仅是 ID。

我可以等待学生对象可用,然后使用引用对每个 classId 的 API 进行额外调用以获取详细信息,但我不确定如何,甚至是否将其与学生对象集成.

这是我目前所拥有的。

function findOne() {
  vm.student = StudentsResource.get({
    studentId: $stateParams.studentId
  });
};

这是我从我的 API 得到的结果

{
  "studentId": 1,
  "name": "Henrietta",
  "enrolledClasses": [
    {
      "enrollmentId": 12,
      "startDate": "2015-08-06T17:43:14.000Z",
      "endDate": null,
      "class": 15
    },
      "enrollmentId": 13,
      "startDate": "2015-08-06T17:44:14.000Z",
      "endDate": null,
      "class": 29
    }
}

对于课程详细信息,我可以一次一个,但还没有弄清楚如何等到学生对象可用时将它们推入其中。也不是如何正确地推动它们......

{ 
  "classId": 15,
  "name": "Algebra",
  "description": "..."
}

{
  "classId": 29,
  "name": "Physics",
  "description": "..."
}

问题

通过注册将学生和班级的详细信息合并为一个对象是否是一种好习惯?

  • 如果是这样,最明确的方法是什么?
  • 如果不是,还有什么有效的方法?

请记住,该应用将允许更改学生详细信息和注册,但不允许更改班级名称或描述的详细信息。因此,如果 Angular 要为对象发送 PUT,它不应该尝试发送任何类的详细信息,而只发送引用。这将在服务器端强制执行以保护数据,但为避免错误,客户端不应尝试。

作为背景,我使用 SailsJS 和 PostgreSQL 作为后端 API。

【问题讨论】:

  • 系统有多少个班级?你能在一个请求中得到所有这些吗?
  • 这在很大程度上取决于您需要在应用程序中对此进行哪些操作。您可能不需要合并数据,并且可以根据需要请求详细信息。或者,如上所述,将所有类放在前面并根据需要进行查找。使用类 ID 作为键的 hashmap 将使查找变得非常简单。如果您确实希望将它们结合起来,那么在向服务器发送更新时删除拦截器中的详细信息并不难
  • @OriDrori 在此示例中,任何给定学生一次只能注册少于 10 个课程。但多年来,这可能会增加到不到 50 个。
  • 正如@charlietfl 所说 - 我会在应用程序加载时获得所有类的列表,对它们进行哈希处理,并根据需要使用。无论如何,您不要将它们与学生对象组合来显示信息。
  • @charlietfl 我正在寻找使这个干净和易于理解的想法。手动添加对象以替换参考值似乎很草率,只是稍后必须捕获并剥离它。但是,当 Class 和 Enrollments 之间的一对多关系明确时,不将所有三层深度存储在一个对象中似乎也很草率。这种通过关联进行的 M 对 M 似乎是一种足够普遍的需求,因此会有一个完善的模式。我只是还没找到。

标签: angularjs postgresql orm sails.js ngresource


【解决方案1】:

所以基本上在 Sailsjs 方面,您应该覆盖 StudentController.js 中的 findOne 函数。这是假设您使用的是蓝图。

// StudentController.js
module.exports = {
  findOne: function(req, res) {
    Student.findOne(req.param('id')).populate('enrollments').then(function(student){
      var studentClasses = Class.find({
        id: _.pluck(student.enrollments, 'class')
      }).then(function (classes) {
        return classes
      })
      return [student, classes]
    }).spread(function(student, classes){
      var classes = _.indexBy(classes, 'id')
      student.enrollments = _.map(student.enrollments, function(enrollment){
        enrollment.class = classes[enrollment.class]
        return enrollment
      })
      res.json(200, student)
    }).catch(function(err){
      if (err) return res.serverError(err)
    })
  }
}

// Student.js

module.exports = { 
  attributes: {
    enrollments: {
      collection: 'enrollment',
      via: 'student'
    } 
    // Rest of the attributes..   
  }
}

// Enrollment.js

module.exports = {
  attributes: {
    student: {
      model: 'student'
    }
    class: {
      model: 'class'
    }
    // Rest of the attributes...
  }
}

// Class.js

module.exports: {
  attributes: {
    enrollments: {
      collection: 'enrollment',
      via: 'class'
    }
    // Rest of the attrubutes
  }
}

说明:
1. 使用 Lo-dash 的 _.pluck 函数重新调整了一个 classId 数组,我们找到了我们想要填充的所有类。然后我们使用承诺链 .spread(),创建一个由 classid 索引的数组,并将 classIds 映射到我们希望填充到从 Student.findOne() 返回的学生的注册中的实际类实例。
2. 以正确的班级深度填充注册的学生返回。

来源:Sails.js populate nested associations

【讨论】:

  • 对于 Read 操作,这很有效(在 .then 更正之后)。但副作用是,当客户端从学生记录中删除注册时,数据库中的记录不会被删除。它是孤立的,学生的值为空,但仍显示在班级的注册列表中,但学生 ID 为空。似乎我也必须覆盖更新蓝图来处理这个问题。现在它再次让我觉得很老套。作为一种不同的方法,我正在考虑使用注册模型,因为它是学生和班级控制器内部的自己的角度控制器。
  • 当您删除记录时,为什么不调用 delete /enrollment/:id 方法而不是更新学生记录。这是自动级联删除学生记录中的关联注册。另一种解决方案是不实际删除并拥有一个名为 isDeleted 的字段并将其设为 false。然后,您必须覆盖所有蓝图以始终使用 isDeleted == true 进行查询。不幸的是,这些东西在 Sails 中并不像在 Rails 中那样容易。一旦你编写了一次代码,尽管它很容易重新调整用途。
猜你喜欢
  • 2018-05-20
  • 2016-04-18
  • 2015-02-15
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
  • 2014-02-12
  • 2015-12-29
相关资源
最近更新 更多