gpt4 book ai didi

c# - List.ForEach(Action) 和 Sql 事务的奇怪行为

转载 作者:太空宇宙 更新时间:2023-11-03 14:55:52 24 4
gpt4 key购买 nike

场景

我正在编写一个系统来进行考试。考试负责人(Invigilator)开始考试,此时允许参加考试的人(Candidates)开始考试。如果考生试图提前开始,他们会收到一条消息,告诉他们等待监考员。记录两个开始时间(考试开始和考生开始)。

当监考员开始考试时,我们设置 exam start time对于考试,我们然后找出每个考生被允许参加考试的时间,并将其添加到 exam start time 中。 ,从而给了我们我所说的 scheduled finish .

public void SetExamStart(Exam exam, List<ExamCandidate> examCandidates)
{
DateTime startTime = _timeService.GetCurrentDateTime();

exam.ExamStarted = startTime;

_work.ExamRepository.Update(exam);

examCandidates.ForEach(ec =>
{
ExamPaper examPaper = ec.ExamPaper;

if (!examPaper.ExamDuration.HasValue)
{
return;
}

Int32 examPaperDuration = examPaper.ExamDuration.Value;

DateTime scheduledFinish = startTime.AddMinutes(examPaperDuration);

ec.ScheduledFinish = scheduledFinish;

_work.ExamCandidateRepository.Update(ec);
});
}

对存储库的调用在同一个事务中。 ConnectionService是依赖注入(inject)到版本库,版本库注入(inject)UnitOfWork (_work),均基于每个网络请求。

public virtual void Update(TEntity entity)
{
IDbConnection connection = ConnectionService.Connection;

try
{
connection.Execute(_queryGenerator.UpdateQuery, entity, ConnectionService.Transaction);
}
catch (SqlException ex)
{
throw new DataAccessException("An error occured on query execution", ex);
}
}

当候选人试图开始时:

public void StartCandidateExam(Guid examCandidateId)
{
ExamCandidate examCandidate = _work.ExamCandidateRepository.Get(examCandidateId);

Exam exam = examCandidate.Exam;

if (!exam.ExamStarted.HasValue) {
throw new ExamNotStartedException("Please wait for the invigilator to start the exam");
}

_candidateExamService.StartExam(examCandidate);

_work.SaveChanges();
}

public void StartExam(ExamCandidate examCandidate)
{
DateTime currentTime = _timeService.GetCurrentDateTime();

examCandidate.Started = currentTime;

_work.ExamCandidateRepository.Update(examCandidate);
}

在整个项目中,我使用 Lazy<T>在某些实体上。如 ExamPaper ExamCandidate 上的属性(property)实体。如下所示:

public class ExamCandidate
{
//other properties

public DateTime? ScheduledFinish { get; set; }

public int ExamPaperID { get; set; }

public LazyEntity<ExamPaper> ExamPaper { get; set; }
}

public class LazyEntity<T> : Lazy<T>
{
public LazyEntity(Func<T> func) : base(func) {}

public static implicit operator T(LazyEntity<T> lazy)
{
return lazy.Value;
}
}

// setting the lazy in the exam candidate repository
examCandidate.ExamPaper = new LazyEntity<ExamPaper>(() =>
{
return Work.ExamPaperRepository.Get(examCandidate.ExamPaperID);
});

问题:

考生在监考员之后非常开始考试,这导致他们的 ScheduledFinish 没有被设置。这对于几秒钟后开始的其他候选人来说效果很好。

这是日志:

+------------------------+-------------------------+
| Log Type | Log Date |
+------------------------+-------------------------+
| Exam Started | 2018-03-08 15:00:58.370 |
| Candidate Exam Started | 2018-03-08 15:00:58.387 |
+------------------------+-------------------------+

+-------------------------+-------------------------+--------+-------------+
| Started | ScheduledFinish | ExamID | ExamPaperID |
+-------------------------+-------------------------+--------+-------------+
| 2018-03-08 15:00:58.387 | NULL | 42 | 34 |
| 2018-03-08 15:01:01.727 | 2018-03-08 15:30:58.370 | 42 | 34 |
| 2018-03-08 15:01:02.507 | 2018-03-08 15:30:58.370 | 42 | 56 |
| 2018-03-08 15:01:02.770 | 2018-03-08 15:30:58.370 | 42 | 56 |
| 2018-03-08 15:01:02.960 | 2018-03-08 15:30:58.370 | 42 | 34 |
+-------------------------+-------------------------+--------+-------------+

我看不出这是什么原因,考试的开始和每个预定结束时间的设置是在同一个操作中完成的,在同一个事务下,并且在这发生之前考生不能开始。

有什么我想念的吗?

--编辑澄清一下,这个问题在不到一年的时间里发生了两次。两次在监考员开始后考生很快就开始了。

最佳答案

我认为您的问题是您首先在 SetExamStart 中设置 exam.ExamStarted = startTime,而不是为考生设置 ScheduledFinish。可以调用 StartCandidateExam,因为 ExamStarted.HasValue 为真,但您的 ExamCandidate ScheduledFinish 可以为空。

将您的 SetExamStart 更改为此以确保设置了 ScheduledFinish:

public void SetExamStart(Exam exam, List<ExamCandidate> examCandidates)
{
DateTime startTime = _timeService.GetCurrentDateTime();

examCandidates.ForEach(ec =>
{
ExamPaper examPaper = ec.ExamPaper;

if (!examPaper.ExamDuration.HasValue)
{
return;
}

Int32 examPaperDuration = examPaper.ExamDuration.Value;

DateTime scheduledFinish = startTime.AddMinutes(examPaperDuration);

ec.ScheduledFinish = scheduledFinish;

_work.ExamCandidateRepository.Update(ec);
});

exam.ExamStarted = startTime;

_work.ExamRepository.Update(exam);
}

您可能必须更改此逻辑

 if (!examPaper.ExamDuration.HasValue) 
...

也是。

关于c# - List<T>.ForEach(Action) 和 Sql 事务的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49194161/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com