EF Core и SQL Server - без перекрывающихся диапазонов дат - PullRequest
0 голосов
/ 09 апреля 2020

Я боролся с ситуацией, в которой я не нашел решения на данный момент. У меня есть приложение. net core 3.1, использующее EF Core, которое должно отслеживать время выполнения задач для пользователей, у этих пользователей не может быть перекрывающегося времени.

Например, пользователь 1 не может работать с 10:00 до 11:00 указанного дня c дважды или с 9:30 до 10:20, а также с 10:00 до 11:00, поскольку время перекрывается.

Я храню StartDate и EndDate этих задач, а также UserId в моей таблице TaskTime.

Я успешно провел проверки на уровне приложения и триггер в базе данных, который остановит это происходит, кроме одного сценария:

Если у меня есть два или более запросов, приходящих в одно и то же время или в течение миллисекунд друг от друга, проверки приложения бесполезны, поскольку обе вставки будут выполняться одновременно, и база данных триггер не останавливает вставку перекрывающихся записей, либо триггер вообще не выполняется в этих сценариях ios, либо он фактически выполняется, но откат, похоже, не работает. Триггер работает в «медленном сценарии», например, когда один пользователь добавляет одну запись за раз, и время между этими запросами остается свободным.

Вот мой триггер:

create trigger NoOverlappingRanges on TaskTime for insert, update as
begin
    if exists(
        select 1 from TaskTime TT inner join inserted NV on 
        (
            (
                TT.UserId = NV.UserId 
                and 
                TT.StartDate <= NV.EndDate 
                and 
                NV.StartDate <= TT.EndDate
                and
                TT.Id <> NV.Id
            )
        )
    )
    begin
        raiserror('Time ranges should not overlap', 16, 1)
        rollback transaction
    end
end

Что касается прикладного уровня, потоки не будут знать о существовании друг друга, пока не станет слишком поздно, и если параллелизма не будет, они будут работать отлично.

Большое спасибо всем за чтение и любую возможную помощь .

Я добавлю здесь соответствующий код приложения, чтобы быть более подробным:

public async Task<RequestFeedback> AddTime(int TaskId, Guid UserId, Guid CreatedById, DateTime StartDate, DateTime EndDate, int TimeOffset = 0)
{
    RequestFeedback request = new RequestFeedback();
    try
    {
        EndDate = EndDate.ToUTCData(TimeOffset);
        StartDate = StartDate.ToUTCData(TimeOffset);
        TaskTime time = new TaskTime
        {
            CreatedById = CreatedById,
            Disabled = false,
            EndDate = EndDate,
            RowDate = DateTime.UtcNow,
            StartDate = StartDate,
            TaskId = TaskId,
            UserId = UserId
        };

        ICollection<TaskTime> times = await db.TaskTime.Where(a => a.UserId == UserId && !a.EndDate.HasValue).ToListAsync();
        if (times.Count > 1)
        {
            db.RemoveRange(times);
            await db.SaveChangesAsync();
            request.Success = false;
            request.Title = "There were multiple times being tracked";
            request.Text = "To avoid time conflicts and overlaps, all open tracked times where cancelled";
            return request;
        }

        ICollection<DateTime> Overlaps = await db.TaskTime.Where(a => a.UserId == UserId && a.StartDate <= time.EndDate && time.StartDate <= a.EndDate.Value).OrderBy(a => a).Select(a => a.StartDate).ToListAsync();
        if (Overlaps.Any())
        {
            DateTime Overlap = Overlaps.FirstOrDefault();
            time.EndDate = Overlap.AddSeconds(-1);
            if (time.EndDate < time.StartDate)
            {
                request.Success = false;
                request.Title = "Could not add this time slot with a proper timeframe";
                request.Text = "The given time would either overlap with other time slots or be smaller than 0 seconds.";
            }
            else
            {
                db.Add(time);
                await db.SaveChangesAsync();
                request.Success = true;
                request.Title = "Time slot added successfully";
                request.Text = $"Due to overlaps with other time slots, this end date was set to {time.EndDate.FromUTCData(TimeOffset).DateFormat()} to avoid conflicts.";
            }
        }
        else
        {
            if (time.EndDate < time.StartDate)
            {
                request.Success = false;
                request.Title = "Could not add this time slot with a proper timeframe";
                request.Text = "The given time would be smaller than 0 seconds.";
            }
            else
            {
                db.Add(time);
                await db.SaveChangesAsync();
                request.Success = true;
                request.Title = "Time slot added successfully";
            }
        }
        return request;
    }
    catch (Exception e)
    {
        await errorLogService.InsertException(e); throw;
    }
}

Еще раз, спасибо за ваше время

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...