Revised Plan: Eliminating Duplicate Production Plan TRN IDs
This revised plan details the focused approach for securing PlanTrnId (prefixes 'P' and 'X') using the LastDocumentNumbers sequencing table. We will perform database-level pre-seeding and only modify PlanTrnId insertion routines in the repository imports during this round. No changes will be made to PlanNo or other tables.
1. Simple Recovery Model & Transaction Safety
No changes are required for backup/restore recovery models. SQL Server’s recovery model (Simple vs. Full) only affects transaction log maintenance and truncate/backup behaviors. Atomicity, isolation, and row-level locking (ACID properties) are fully guaranteed in the Simple recovery model. Row locks acquired during transaction execution or update operations behave exactly the same way.
2. Database Migration Plan (Pre-Seeding)
To avoid complex dynamic seeding logic in runtime C# code, a new SQL database migration script will be created to ensure the LastDocumentNumbers table is populated.
If existing records are present, we seed using the MAX identifier from PrdnPlan1. Otherwise, the sequence is initialized to 0.
Migration Script: V0_0_0_0_0_14__Seed_LastDocumentNumbers.sql
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'LastDocumentNumbers')
BEGIN
-- Seed for 'P' (Production Plan TRN ID) if not exists
IF NOT EXISTS (SELECT 1 FROM LastDocumentNumbers WHERE DocType = 'P')
BEGIN
INSERT INTO LastDocumentNumbers (DocType, LastNumber, Description)
SELECT 'P', COALESCE(MAX(CAST(RIGHT(PlanTrnId, 6) AS INT)), 0), 'Production Plan TRN ID'
FROM PrdnPlan1 WHERE LEFT(PlanTrnId, 1) = 'P';
END
-- Seed for 'X' (Scrap TRN ID) if not exists
IF NOT EXISTS (SELECT 1 FROM LastDocumentNumbers WHERE DocType = 'X')
BEGIN
INSERT INTO LastDocumentNumbers (DocType, LastNumber, Description)
SELECT 'X', COALESCE(MAX(CAST(RIGHT(PlanTrnId, 6) AS INT)), 0), 'Scrap TRN ID'
FROM PrdnPlan1 WHERE LEFT(PlanTrnId, 1) = 'X';
END
-- Seed future types with 0 if not exists (preparing table for later rounds)
IF NOT EXISTS (SELECT 1 FROM LastDocumentNumbers WHERE DocType = 'B')
INSERT INTO LastDocumentNumbers (DocType, LastNumber, Description) VALUES ('B', 0, 'Bill TRN ID');
IF NOT EXISTS (SELECT 1 FROM LastDocumentNumbers WHERE DocType = 'J')
INSERT INTO LastDocumentNumbers (DocType, LastNumber, Description) VALUES ('J', 0, 'Jobwork TRN ID');
IF NOT EXISTS (SELECT 1 FROM LastDocumentNumbers WHERE DocType = 'Y')
INSERT INTO LastDocumentNumbers (DocType, LastNumber, Description) VALUES ('Y', 0, 'Y Type TRN ID');
END3. Runtime C# Code Design
Since sequences are pre-seeded in the database:
- No changes are needed to
UtilityMethodsRepository.GetNextDocumentNumberorPrdnPlanController.cs(single-record actions already callGetNextDocumentNumbercorrectly). - Surgical repository updates will be applied to the bulk import routines inside
PrdnPlanRepository.cs.
4. Specific Program Changes
Program 1: PrdnPlanRepository.cs
We will modify the sequence generation queries inside ImportSlittingIssue and ImportTransferPlan.
Change A: ImportSlittingIssue
We will replace the current query declarations:
- Remove
maxTrnIdQueryentirely. - Update
updateTempPlanTrnIdto reserve a block of numbers fromLastDocumentNumbersand update the temporary table in a single SQL operation:
var updateTempPlanTrnId = @"
DECLARE @Count INT;
SELECT @Count = COUNT(*) FROM #temp;
DECLARE @UpdatedTable TABLE (LastNumber INT);
UPDATE LastDocumentNumbers
SET LastNumber = LastNumber + @Count
OUTPUT INSERTED.LastNumber INTO @UpdatedTable
WHERE DocType = 'P';
DECLARE @LastNumber INT;
SELECT @LastNumber = LastNumber FROM @UpdatedTable;
WITH A(rowno, tempid) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY id) AS Rowno, id AS tempid FROM #temp
),
B(tempid, plantrnid) AS
(
SELECT tempid, FORMAT((@LastNumber - @Count) + A.rowno, '000000') AS plantrnid FROM A
)
UPDATE #temp SET #temp.plantrnid = CONCAT('P', B.plantrnid) FROM B
WHERE #temp.id = B.tempid;";In the execution logic of ImportSlittingIssue (lines ~1604-1605):
connection.Execute(updateTempPlanTrnId);Change B: ImportTransferPlan
- Remove
maxPlanTrnIdQueryentirely. - Update
updateTempPlanTrnId(same definition as above). - Update
secondInsertto atomically reserve a second block of IDs for theMovementType = 'R'inserts directly in the query, eliminating the need to pass@maxplantrnid:
var secondInsert = @"
DECLARE @Count INT;
SELECT @Count = COUNT(*) FROM #temp;
DECLARE @UpdatedTable TABLE (LastNumber INT);
UPDATE LastDocumentNumbers
SET LastNumber = LastNumber + @Count
OUTPUT INSERTED.LastNumber INTO @UpdatedTable
WHERE DocType = 'P';
DECLARE @LastNumber INT;
SELECT @LastNumber = LastNumber FROM @UpdatedTable;
WITH A(rowno, tempid) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY id) AS Rowno, id AS tempid
FROM #temp
),
B(tempid, plantrnid) AS
(
SELECT tempid, FORMAT((@LastNumber - @Count) + A.rowno, '000000') AS plantrnid FROM A
),
C(itemid, gradeid, widthid, coatingid, wattlossid) AS
(
SELECT TOP 1 itemid, gradeid, widthid, coatingid, wattlossid
FROM prdnplan1
WHERE yearplanno = @yearplanno
ORDER BY id
),
D(planno, plantrnid, reftrnid, itemid, gradeid, widthid, coatingid, wattlossid, qty, qty1,
MovementType, YearPlanNo, EffectiveWidth, noofslits, partyid) AS
(
SELECT @planno, CONCAT('P', B.plantrnid) AS plantrnid,
billtrnid AS reftrnid, C.itemid, C.gradeid, C.widthid, C.coatingid, C.wattlossid, J1.qty,
J1.qty1, @MovementType, @yearPlanNo, W.Coilsize AS EffectiveWidth,
@noofslits, @transferplanto AS partyid
FROM #temp T
LEFT JOIN jobwork1 J1 ON T.billtrnid = J1.trnid
LEFT JOIN DprWidth W ON J1.widthid = W.Widthid
LEFT JOIN B ON T.id = B.tempid
LEFT JOIN C ON 1 = 1
)
INSERT INTO PrdnPlan1(planno, plantrnid, reftrnid, itemid, gradeid, widthid, coatingid, wattlossid, qty, qty1,
MovementType, YearPlanNo, EffectiveWidth, noofslits, partyid)
SELECT planno, plantrnid, reftrnid, itemid, gradeid, widthid, coatingid, wattlossid, qty, qty1,
MovementType, YearPlanNo, EffectiveWidth, noofslits, partyid
FROM D;";In the execution logic of ImportTransferPlan (lines ~1972-1994):
connection.Execute(updateTempPlanTrnId);
string? nullValue = null;
connection.Execute(firstInsert, new
{
planno = mainData.PlanNo,
yearPlanNo = mainData.YearPlanNo,
noofslits = nullValue,
movementType = "I"
});
connection.Execute(secondInsert, new
{
yearPlanNo = mainData.YearPlanNo,
planno = mainData.PlanNo,
movementType = "R",
noofslits = "1",
transferPlanTo
});