Skip to content

Commit 0f8a5e5

Browse files
authored
Merge pull request #54 from Avanade/v3.0.2
v3.0.2
2 parents e3df44a + b3a112b commit 0f8a5e5

File tree

9 files changed

+92
-8
lines changed

9 files changed

+92
-8
lines changed

CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
Represents the **NuGet** versions.
44

5+
## v3.0.2
6+
- *Fixed:* The completion stage was incorrectly using the `EntityKey` versus `TableKey` (where using global identifiers) for the version hashing resulting in re-publishing where not required; code-generation template corrected and is required for fix.
7+
58
## V3.0.1
6-
- *Fixed:* Generated `ExecuteBatch.sql` fixed to not invoke `sys.fn_cdc_get_min_lsn` twice but use returned result as intended.
9+
- *Fixed:* Generated `ExecuteBatch.sql` fixed to not invoke `sys.fn_cdc_get_min_lsn` twice but use returned result as intended.
710

811
## v3.0.0
912
- *Enhancement:* Major **"Sidecar"** feature added based on feedback from the community.

Common.targets

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>3.0.1</Version>
3+
<Version>3.0.2</Version>
44
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
55
<Authors>NTangle Developers</Authors>
66
<Company>Avanade</Company>

samples/SqlServerDemo/SqlServerDemo.Database/Schema/NTangle/Stored Procedures/Generated/spContactBatchExecute.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ BEGIN
198198
LEFT OUTER JOIN [Legacy].[ContactMapping] AS [cm] ON ([cm].[ContactId] = [c].[ContactId])
199199
LEFT OUTER JOIN [NTangle].[IdentifierMapping] AS [_im] ON ([_im].[Schema] = N'Legacy' AND [_im].[Table] = N'Contact' AND [_im].[Key] = CAST([_chg].[ContactId] AS NVARCHAR(128)))
200200
LEFT OUTER JOIN [NTangle].[IdentifierMapping] AS [_im1] ON ([_im1].[Schema] = 'Legacy' AND [_im1].[Table] = 'Contact' AND [_im1].[Key] = CAST([c].[AlternateContactId] AS NVARCHAR(128)))
201-
LEFT OUTER JOIN [NTangle].[VersionTracking] AS [_vt] ON ([_vt].[Schema] = N'Legacy' AND [_vt].[Table] = N'Contact' AND [_vt].[Key] = _im.GlobalId)
201+
LEFT OUTER JOIN [NTangle].[VersionTracking] AS [_vt] ON ([_vt].[Schema] = N'Legacy' AND [_vt].[Table] = N'Contact' AND [_vt].[Key] = CAST([_chg].[ContactId] AS NVARCHAR(128)))
202202
ORDER BY [_Lsn] ASC
203203

204204
-- Related table: '[Legacy].[Address]' - unique name 'Address' - only use INNER JOINS to get what is actually there right now (where applicable).

samples/SqlServerDemo/SqlServerDemo.Test/ContactTest.cs

+40
Original file line numberDiff line numberDiff line change
@@ -165,5 +165,45 @@ public async Task UsePreassignedIdentifiers()
165165
ClassicAssert.NotNull(c.Address?.GlobalId);
166166
ClassicAssert.AreEqual("C88", c.Address?.GlobalAlternateAddressId);
167167
}
168+
169+
[Test]
170+
public async Task NoPublishSameHash()
171+
{
172+
using var db = SqlServerUnitTest.GetDatabase();
173+
var logger = UnitTest.GetLogger<ContactOrchestrator>();
174+
175+
// Update contact 1.
176+
var script = "UPDATE [Legacy].[Contact] SET [Phone] = '8888' WHERE [ContactId] = 1";
177+
await db.SqlStatement(script).NonQueryAsync().ConfigureAwait(false);
178+
await UnitTest.Delay().ConfigureAwait(false);
179+
180+
var imp = new InMemoryPublisher(logger);
181+
var cdc = new ContactOrchestrator(db, imp, JsonSerializer.Default, UnitTest.GetSettings(), logger, new IdentifierGenerator());
182+
var cdcr = await cdc.ExecuteAsync().ConfigureAwait(false);
183+
UnitTest.WriteResult(cdcr, imp);
184+
185+
// Assert/verify the results.
186+
ClassicAssert.NotNull(cdcr);
187+
ClassicAssert.IsTrue(cdcr.IsSuccessful);
188+
189+
var events = imp.GetEvents();
190+
ClassicAssert.AreEqual(1, events.Length);
191+
192+
// Update contact 1 again with same value.
193+
await db.SqlStatement("UPDATE [Legacy].[Contact] SET [Phone] = '7777' WHERE [ContactId] = 1").NonQueryAsync().ConfigureAwait(false);
194+
await db.SqlStatement("UPDATE [Legacy].[Contact] SET [Phone] = '8888' WHERE [ContactId] = 1").NonQueryAsync().ConfigureAwait(false);
195+
await UnitTest.Delay().ConfigureAwait(false);
196+
197+
imp.Reset();
198+
cdcr = await cdc.ExecuteAsync().ConfigureAwait(false);
199+
UnitTest.WriteResult(cdcr, imp);
200+
201+
// Assert/verify the results.
202+
ClassicAssert.NotNull(cdcr);
203+
ClassicAssert.IsTrue(cdcr.IsSuccessful);
204+
205+
events = imp.GetEvents();
206+
ClassicAssert.AreEqual(0, events.Length);
207+
}
168208
}
169209
}

samples/SqlServerSidecarDemo/SqlServerSidecarDemo.Test/ContactTest.cs

+41
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,47 @@ public async Task GenerateAllIdentifiers()
118118
ClassicAssert.AreEqual(c.Address?.GlobalAlternateAddressId, c2.Address?.GlobalAlternateAddressId);
119119
}
120120

121+
[Test]
122+
public async Task NoPublishSameHash()
123+
{
124+
using var db = SqlServerSidecarUnitTest.GetDatabase();
125+
using var sdb = SqlServerSidecarUnitTest.GetSidecarDatabase();
126+
var logger = UnitTest.GetLogger<ContactOrchestrator>();
127+
128+
// Update contact 1.
129+
var script = "UPDATE [Legacy].[Contact] SET [Phone] = '8888' WHERE [ContactId] = 1";
130+
await db.SqlStatement(script).NonQueryAsync().ConfigureAwait(false);
131+
await UnitTest.Delay().ConfigureAwait(false);
132+
133+
var imp = new InMemoryPublisher(logger);
134+
var cdc = new ContactOrchestrator(db, sdb, imp, JsonSerializer.Default, UnitTest.GetSettings(), logger, new IdentifierGenerator());
135+
var cdcr = await cdc.ExecuteAsync().ConfigureAwait(false);
136+
UnitTest.WriteResult(cdcr, imp);
137+
138+
// Assert/verify the results.
139+
ClassicAssert.NotNull(cdcr);
140+
ClassicAssert.IsTrue(cdcr.IsSuccessful);
141+
142+
var events = imp.GetEvents();
143+
ClassicAssert.AreEqual(1, events.Length);
144+
145+
// Update contact 1 again with same value.
146+
await db.SqlStatement("UPDATE [Legacy].[Contact] SET [Phone] = '7777' WHERE [ContactId] = 1").NonQueryAsync().ConfigureAwait(false);
147+
await db.SqlStatement("UPDATE [Legacy].[Contact] SET [Phone] = '8888' WHERE [ContactId] = 1").NonQueryAsync().ConfigureAwait(false);
148+
await UnitTest.Delay().ConfigureAwait(false);
149+
150+
imp.Reset();
151+
cdcr = await cdc.ExecuteAsync().ConfigureAwait(false);
152+
UnitTest.WriteResult(cdcr, imp);
153+
154+
// Assert/verify the results.
155+
ClassicAssert.NotNull(cdcr);
156+
ClassicAssert.IsTrue(cdcr.IsSuccessful);
157+
158+
events = imp.GetEvents();
159+
ClassicAssert.AreEqual(0, events.Length);
160+
}
161+
121162
[Test]
122163
public async Task UsePreassignedIdentifiers()
123164
{

src/NTangle/Cdc/EntityOrchestratorCore.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ protected internal Task ConsolidateAsync(EntityOrchestratorResult<TEntityEnvelop
307307

308308
// Consolidate the results.
309309
var coll = new TEntityEnvelopeColl();
310-
foreach (var grp in result.Result.GroupBy(x => new { x.EntityKey }))
310+
foreach (var grp in result.Result.GroupBy(x => new { Key = x is IGlobalIdentifier gi ? gi.TableKey : x.EntityKey }))
311311
{
312312
// Find delete and use.
313313
var item = grp.Where(x => x.DatabaseOperationType == CdcOperationType.Delete).FirstOrDefault();
@@ -407,7 +407,7 @@ protected internal async Task<List<VersionTracker>> VersionAsync(EntityOrchestra
407407
if ((result.IsExplicitExecution && result.ExplicitOptions!.AlwaysPublishEvents) || item.DatabaseTrackingHash == null || item.DatabaseTrackingHash != entity.ETag)
408408
{
409409
coll.Add(item);
410-
tracking.Add(new VersionTracker { Key = entity.EntityKey.ToString(), Hash = entity.ETag });
410+
tracking.Add(new VersionTracker { Key = entity is IGlobalIdentifier gi ? gi.TableKey.ToString() : entity.EntityKey.ToString(), Hash = entity.ETag });
411411
}
412412

413413
// Clear ETag where delete; i.e. non sensical.

tools/NTangle.CodeGen/Templates/SpExecuteBatch_sql.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ BEGIN
245245
LEFT OUTER JOIN [{{Root.CdcSchema}}].[{{Root.IdentifierMappingTable}}] AS [{{IdentifierMappingAlias}}] ON ([{{IdentifierMappingAlias}}].[Schema] = '{{IdentifierMappingSchema}}' AND [{{IdentifierMappingAlias}}].[Table] = '{{IdentifierMappingTable}}' AND [{{IdentifierMappingAlias}}].[Key] = CAST([{{IdentifierMappingParent.Parent.Alias}}].[{{IdentifierMappingParent.Name}}] AS NVARCHAR(128)))
246246
{{/ifval}}
247247
{{/each}}
248-
LEFT OUTER JOIN [{{Root.CdcSchema}}].[{{Root.VersionTrackingTable}}] AS [_vt] ON ([_vt].[Schema] = N'{{Schema}}' AND [_vt].[Table] = N'{{Table}}' AND [_vt].[Key] = {{#if IdentifierMapping}}_im.GlobalId){{else}}{{#ifeq PrimaryKeyColumns.Count 1}}{{#each PrimaryKeyColumns}}CAST([_chg].[{{Name}}] AS NVARCHAR(128))){{/each}}{{else}}CONCAT({{#each PrimaryKeyColumns}}CAST([_chg].[{{Name}}] AS NVARCHAR(128))){{#unless @last}}, ',', {{/unless}}{{/each}}){{/ifeq}}{{/if}}
248+
LEFT OUTER JOIN [{{Root.CdcSchema}}].[{{Root.VersionTrackingTable}}] AS [_vt] ON ([_vt].[Schema] = N'{{Schema}}' AND [_vt].[Table] = N'{{Table}}' AND [_vt].[Key] = {{#ifeq PrimaryKeyColumns.Count 1}}{{#each PrimaryKeyColumns}}CAST([_chg].[{{Name}}] AS NVARCHAR(128))){{/each}}{{else}}CONCAT({{#each PrimaryKeyColumns}}CAST([_chg].[{{Name}}] AS NVARCHAR(128))){{#unless @last}}, ',', {{/unless}}{{/each}}){{/ifeq}}
249249
ORDER BY [_Lsn] ASC
250250

251251
{{#each CdcJoins}}

tools/NTangle.Template/content/AppName.CodeGen/AppName.CodeGen.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<Nullable>enable</Nullable>
66
</PropertyGroup>
77
<ItemGroup>
8-
<PackageReference Include="NTangle.CodeGen" Version="3.0.1" />
8+
<PackageReference Include="NTangle.CodeGen" Version="3.0.2" />
99
</ItemGroup>
1010
<ItemGroup>
1111
<None Update="ntangle.yaml">

tools/NTangle.Template/content/AppName.Publisher/AppName.Publisher.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<EmbeddedResource Include="Resources\**\*" />
2828
</ItemGroup>
2929
<ItemGroup>
30-
<PackageReference Include="NTangle" Version="3.0.1" />
30+
<PackageReference Include="NTangle" Version="3.0.2" />
3131
<PackageReference Include="CoreEx.Azure" Version="3.30.0" />
3232
<!--#if (implement_publisher_console) -->
3333
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />

0 commit comments

Comments
 (0)