Как удалить записи до указанной даты в Entity Framework Core, за исключением последних? - PullRequest
0 голосов
/ 19 июня 2020

Как я могу удалить все записи акций, кроме последних, которые были созданы до указанной c даты, в Entity Framework Core. Я не могу определить требуемый запрос LINQ, но мне удалось собрать SQL, который должен выполнить эту работу:

--
-- Parameters. 
--
DECLARE @PurgeDate DATETIME = DATEADD(day, -7, GETDATE());
DECLARE @RegionId INT = 28;

DECLARE @StockCodes TABLE(
    StockCode NVARCHAR(10)
);

-- Could be a significant number
INSERT INTO @StockCodes VALUES ('ABC123'), ('DEF123') /* etc... */;

--
-- Get stock records that are newer than the purge date or the latest record if not. 
-- This ensures there is always at least one stock record for a stock code.
--
WITH LatestStockRecords
AS
(
    SELECT s.*, [RowNumber] = ROW_NUMBER() OVER (PARTITION BY s.[StockCode] ORDER BY s.[CreatedAt] DESC)
    FROM StockRecords AS s
        INNER JOIN Locations AS l
            ON s.[LocationId] = l.[Id]
    WHERE l.[RegionId] = @RegionId
        AND s.[StockCode] IN (SELECT * FROM @StockCodes)
)
SELECT *.[Id]
INTO #_STOCK_RECORD_IDS
FROM LatestStockRecords
WHERE [CreatedAt] >= @PurgeDate
    OR [RowNumber] = 1;
    
--
-- Delete the stock records that do not appear in the latest stock records temporary table.
--
DELETE s
FROM StockRecords AS s
    INNER JOIN Locations AS l
        ON s.[LocationId] = l.[Id]
WHERE l.[RegionId] = @RegionId
    AND s.[StockCode] IN (SELECT * FROM @StockCodes)
    AND s.[Id] NOT IN (SELECT * FROM #_STOCK_RECORD_IDS);

Может потребоваться удалить значительное количество записей, поэтому производительность должна быть рассмотрение.

РЕДАКТИРОВАТЬ: Удалены DbContext и объекты, поскольку я не думаю, что они имеют отношение к вопросу.

1 Ответ

0 голосов
/ 22 июня 2020

Вот как я в итоге решил проблему. Мне пришлось принудительно выполнить оценку группирующего запроса, поскольку Entity Framework Core, похоже, не поддерживает необходимый запрос на данном этапе.

var regionId = 28;
var stockCodes = new string[] { "ABC123", "DEF123" /* etc... */ };
var purgeDate = DateTime.UtcNow.AddDays(-NumberOfDaysToPurge);

bool IsPurgeable(StockRecord stockRecord)
{
    return stockRecord.CreatedAt >= purgeDate;
}

var latestStockRecordIds = context.StockRecords
    .Where(stockRecord =>
        stockRecord.Location.RegionId == regionId
        && stockCodes.Contains(stockRecord.StockCode))
    .AsEnumerable() // <-- force execution
    .GroupBy(stockRecord => stockRecord.StockCode)
    .SelectMany(group =>
    {
        var orderedStockRecords = group.OrderByDescending(stockRecord => stockRecord.CreatedAt);

        var stockRecords = orderedStockRecords.Count(IsPurgeable) > 0
            ? orderedStockRecords.Where(IsPurgeable)
            : orderedStockRecords.Take(1);

        return stockRecords.Select(stockRecord => stockRecord.Id);
    });

var stockRecordsToRemove = await context.StockRecords
    .Where(stockRecord =>
        stockRecord.Location.RegionId == regionId
        && StockCodeCodes.Contains(stockRecord.StockCode)
        && stockRecord.CreatedAt <= purgeDate
        && !latestStockRecordIds.Contains(stockRecord.Id))
    .ToListAsync();

context.ChangeTracker.AutoDetectChangesEnabled = false;
context.StockRecords.RemoveRange(stockRecordsToRemove);

await context.SaveChangesAsync();
...