首页 > 解决方案 > 一对多验证竞争条件

问题描述

我有两个具有一对多关系的实体。

TripRequest.cs

public class TripRequest
{
    public Guid Id { get; set; }

    public Guid UserId { get; set; }
    public User User { get; set; }

    public Guid TripId { get; set; }
    public Trip Trip { get; set; }
}

Trip.cs

public class Trip
{
    public Guid Id { get; set; }
    public ICollection <TripRequest> Requests { get; set; } = new List<TripRequest>();
}

而且我有一个命令,我想在其中检查行程是否不包含来自用户的其他请求。

public void Handle(CreateRequestCommand command)
{
    var trip = _tripRepository.GetWithInclude(t => t.Requests)
        .FirstOrDefault(x => x.Id.Equals(command.TripId));

    if (trip == null)
    {
        throw new EntityNotFoundException();
    }

    if (trip.Requests.Any(x => x.UserId.Equals(command.UserId)))
    {
        throw new ConflictException();
    }

    var request = new TripRequest
    {
        TripId = command.TripId,
        UserId = command.UserId,
        CreationDate = DateTime.Now
    };

    _requestRepository.Create(request);
}

当检查在流 A 中通过并且用户被添加到流 B 中时,存在竞争条件。接下来,具有相同 UserId 的用户被添加到流 A 中。

我尝试使用 ConcurrencyCheck 属性,并且正在考虑 TripRequest 的复合键。是否可以在数据库端进行此类检查?解决此问题的最佳方法是什么?

标签: c#entity-frameworkvalidationrace-condition

解决方案


您不应该将此视为并发问题,因为您可以使用唯一约束/唯一索引来绝对防止同一(TripId,UserId)有两个 TripRequest,例如:

[Index("UserId","TripId",IsUnique = true)]
public class TripRequest
{
    public Guid Id { get; set; }

    public Guid UserId { get; set; }
    public User User { get; set; }

    public Guid TripId { get; set; }
    public Trip Trip { get; set; }
}

推荐阅读