question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

DMS 0.9.7 Insert trigger fails with composite primary key

See original GitHub issue

Trying to sync a table with a composite primary key on SQL Server via NetCore API to SQLite. On the sql server we have

CREATE TABLE [dbo].[LaborItems](
	[TaskName] [varchar](15) NOT NULL,
	[MaterialCost] [decimal](9, 2) NOT NULL,
	[MinutesSmall] [smallint] NOT NULL,
	[MinutesLarge] [smallint] NOT NULL,
 CONSTRAINT [PK_LaborItems] PRIMARY KEY CLUSTERED 
(
	[TaskName] ASC,
	[MaterialCost] ASC
)

The SQLite table is created by the app (not DMS)

CREATE TABLE LaborItems (
TaskName TEXT NOT NULL COLLATE NOCASE CHECK (length(TaskName) <= 15), 
MaterialCost NUMERIC NOT NULL CHECK (MaterialCost BETWEEN -9999998.99 AND 9999999.99), 
MinutesSmall INTEGER NOT NULL CHECK (MinutesSmall BETWEEN 0 AND 32767), 
MinutesLarge INTEGER NOT NULL CHECK (MinutesLarge BETWEEN 0 AND 32767), 
PRIMARY KEY(TaskName, MaterialCost));

DMS provisions both the server and the client dbs

CREATE TABLE [LaborItems_tracking] (
[TaskName] text NOT NULL COLLATE NOCASE, 
[MaterialCost] numeric NOT NULL COLLATE NOCASE, 
[update_scope_id] [text] NULL COLLATE NOCASE, 
[timestamp] [integer] NULL, 
[sync_row_is_tombstone] [integer] NOT NULL default(0), 
[last_change_datetime] [datetime] NULL, 
 PRIMARY KEY ([TaskName], [MaterialCost]));

CREATE INDEX [LaborItems_tracking_timestamp_index] ON [LaborItems_tracking] (
	 [timestamp] ASC
	,[update_scope_id] ASC
	,[sync_row_is_tombstone] ASC
	,[TaskName] ASC
	,[MaterialCost] ASC
);

CREATE TRIGGER [LaborItems_insert_trigger] AFTER INSERT ON [LaborItems] 

BEGIN
-- If row was deleted before, it already exists, so just make an update
	INSERT OR REPLACE INTO [LaborItems_tracking] (
		[TaskName]
		,[update_scope_id]
		,[timestamp]
		,[sync_row_is_tombstone]
		,[last_change_datetime]
	) 
	VALUES (
		new.[TaskName]
		,NULL
		,replace(strftime('%Y%m%d%H%M%f', 'now'), '.', '')
		,0
		,datetime('now')
	);
END;

The exception thrown on insert is SQLite Error 19: 'NOT NULL constraint failed: LaborItems_tracking.MaterialCost

Issue Analytics

  • State:closed
  • Created 10 months ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
VagueGitcommented, Dec 5, 2022

Hmm … stepping through … the trigger is created correctly as you say, then is later recreated incorrectly. Will investigate and report back

I think I have run this to ground … as far as I am able … When we initialise a new client we sync one table at a time. This saves having to manage snapshots on the server. Once each table is synced we then provision a sync of all tables as that is the only scope used from then on. We do that like this

public static async Task ProvisionAsync(string scopeName = SyncScopes.All)
{//https://github.com/Mimetis/Dotmim.Sync/issues/806#issuecomment-1242102304

    Dictionary<string, string> log = LogHelper.LogDictionary();
    log.Add(nameof(scopeName), scopeName);

    try
    {
        SqliteSyncProvider clientProvider = GetSqliteSyncProvider();
        LocalOrchestrator localOrchestrator = new LocalOrchestrator(clientProvider);
        SyncSetup syncSetup = new SyncScopes().GetSyncSetup(scopeName);
        SyncSet syncSet = await localOrchestrator.GetSchemaAsync(syncSetup);

        ScopeInfo scopeInfo = new ScopeInfo
        {
            Name = scopeName,
            Schema = syncSet,
            Setup = syncSetup,
            Version = SyncVersion.Current.ToString()
        };
        await localOrchestrator.ProvisionAsync(scopeInfo);

        // Get all scope info clients to get minimum Timestamp
        // --------------------------------------
        List<ScopeInfoClient> allScopeInfoClients = await localOrchestrator.GetAllScopeInfoClientsAsync();

        Int64? minServerTimeStamp = allScopeInfoClients.Min(sic => sic.LastServerSyncTimestamp);
        Int64? minClientTimeStamp = allScopeInfoClients.Min(sic => sic.LastSyncTimestamp);
        DateTime? minLastSync = allScopeInfoClients.Min(sic => sic.LastSync);

        // Get (and create) the scope info client for scope ALL
        // --------------------------------------
        ScopeInfoClient scopeInfoClient = await localOrchestrator.GetScopeInfoClientAsync("All");

        if (scopeInfoClient.IsNewScope)
        {
            scopeInfoClient.IsNewScope = false;
            scopeInfoClient.LastSync = minLastSync;
            scopeInfoClient.LastSyncTimestamp = minServerTimeStamp;
            scopeInfoClient.LastServerSyncTimestamp = minClientTimeStamp;
            await localOrchestrator.SaveScopeInfoClientAsync(scopeInfoClient);
        }
    }
    catch (Exception ex)
    {
        Crashes.TrackError(ex, log);
        throw (ex);
    }
}

This line SyncSet syncSet = await localOrchestrator.GetSchemaAsync(syncSetup); returns only a single primary key for LaborItems. I note the same thing happens for another table which also has a compound primary key. DMS provisions the local schema correctly in both cases but then reprovisions the insert trigger to use only the first column of a compound primary key.

0reactions
VagueGitcommented, Dec 24, 2022

Confirmed this is fixed in DMS 0.9.8-beta-0994. A very welcome xmas present thank you. Joyeux Noël

Read more comments on GitHub >

github_iconTop Results From Across the Web

Troubleshooting migration tasks in AWS Database Migration ...
Tasks fail when a primary key is created on a LOB column. In FULL LOB or LIMITED LOB mode, AWS DMS doesn't support...
Read more >
Solved: Trigger on a table with a composite primary key
Hi, I have a table with a primary key that is 3 columns. I want to create a trigger (on update and on...
Read more >
Problems with insert trigger and primary key
Judging by the google results, this is a common error with INSTEAD OF triggers and presumably an identity column. The value for that...
Read more >
Insert into SELECT with composite primary key failing SQL ...
The error I was given reads cannot insert the value NULL into patientID, column does not alloq nulls, insert fails .
Read more >
INSERT Trigger that modifies Primary Key
Hi. I have the following situation: I have two tables, ARItems (Primary Key = RefNo) and ARTrans (Two part Primary Key = RefNo,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found