0

我想了解如何使用 Doctrine 和 Symfony 进行安全的“测试和设置”操作。

我正在建立一个会议安排系统。我有一个实体叫

会议时间,老师和学生

MeetingTime 与 Student 具有可空的多对一关系,与 Teacher 具有多对一关系。

我想强制仅当正确当前为空时才能保存 meetingTime 的学生属性。即,一个学生不应该能够覆盖另一个学生。第一个预定时间的学生获胜。似乎交易会做到这一点。

我正在这样做:

  $saved = true;

  try
  {
    $em->transactional(function($em) use($mtId, $student) {
      $mt = $em->getRepository('MyBundle:MeetingTime')->find($mtId);
      if (is_null($mt->getStudent()))
      {
        $mt->setStudent($student);
        $em->persist($mt);
      }
      else
      {
        throw new Exception();
      }
    });
  }
  catch(Exception $e)
  {
    $saved = false;
  }

  if (!$saved)
  {
// flash "Sorry,, somebody else just grabbed that time".         
  }

如果花费时间,我的 UI 将通过在页面上不显示“这次预订”按钮来应对大部分情况,但当然,如果两个人同时进行操作,数据库拥有最终决定权。

这似乎可行,但这是正确的方法吗?交易安全吗?

我首先使用一个额外的“预订”实体来实现它,该实体与 MeetingTime 一对一,与 Student 多对一,并且对 MeetingTime 有一个独特的约束。这行得通,但是将 Student 作为 MeetingTime 的属性会更好,因为我还希望 MeetingTime 对 Student 和 Teacher 的组合具有独特的约束,因为学生只能与老师预订一次会议。

我知道我可能应该创建自己的 Exception 类,以便知道异常的类型。如果已经设置了正确的学生,我也应该让它感到高兴。

如果重要,数据库是 PostgreSQL。我确信这可以通过触发器非常有效地完成,但是......那是我没有进入的整个世界,保持这个数据库不可知论会很好。

谢谢

4

2 回答 2

0

让存储库查找具有 ID 和 null 学生的 MeetingTime 实体。如果你找到一个,那么你可以设置学生。否则告诉学生他们运气不好。

如果您还没有,您可能必须为此创建自己的存储库类。

除非您有很多学生同时预订,否则我怀疑这将是一个并发问题。

Doctrine 也有一个悲观锁定选项,但有很多警告:http ://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html#pessimistic-锁定

于 2013-08-17T02:12:36.507 回答
0

交易在这里无济于事。它所做的一切都是为了确保刷新成功。它不会锁定任何东西。

在这里阅读:http: //docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html

您可能希望使用乐观锁定,这只需要向您的表中添加版本号并使用 @Version 标记对其进行标记。还有中提琴!尽管您确实需要准备好在刷新时捕获可能的异常,但不再有并发问题。

并考虑将空检查放在 $mt->setStudent 中,这样它总是会发生。

于 2013-08-16T20:28:46.037 回答