- DacFx 162.3.566
- .NET 8, Windows 11
- Environment (local platform and source/target platforms):
SchemaComparison.Compare() detects differences that exist only in comments (including the conventional header comment block above CREATE PROCEDURE), but SchemaComparisonResult.PublishChangesToProject() generates an empty update plan for them and still reports Success = true with zero changed files. Additionally, even when a module has a real body change, the file update rewrites only the statement body — the header comment above CREATE in the project file is never updated from the source.
The two layers disagree about what an object is: the comparison layer diffs the full source text (header included), while the update planner works on the semantic model where the header lives only in the SysCommentsObjectAnnotation (HeaderContents, CreateOffset) and is not actionable. The result is differences that are shown to the user but can never be applied.
dacpac→database carries headers along with real changes, while database→project never does.
Steps to Reproduce:
# point $dac at the DacFx payload (sqlpackage dotnet tool shown; NuGet lib/ works too)
$dac = "$env:USERPROFILE\.dotnet\tools\.store\microsoft.sqlpackage\162.3.566\microsoft.sqlpackage\162.3.566\tools\net8.0\any"
Add-Type -Path "$dac\runtimes\win\lib\net6.0\Microsoft.Data.SqlClient.dll"
Add-Type -Path "$dac\Microsoft.SqlServer.TransactSql.ScriptDom.dll"
Add-Type -Path "$dac\Microsoft.SqlServer.Dac.dll"
Add-Type -Path "$dac\Microsoft.SqlServer.Dac.Extensions.dll"
$work = Join-Path $env:TEMP 'dacfx-comment-repro'
Remove-Item $work -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory "$work\proj\dbo\StoredProcedures" -Force | Out-Null
function Build-Dacpac([string]$path, [string]$sql) {
$model = [Microsoft.SqlServer.Dac.Model.TSqlModel]::new(
[Microsoft.SqlServer.Dac.Model.SqlServerVersion]::Sql150,
[Microsoft.SqlServer.Dac.Model.TSqlModelOptions]::new())
$model.AddObjects($sql)
$meta = [Microsoft.SqlServer.Dac.PackageMetadata]::new()
$meta.Name = 'Repro'; $meta.Version = '1.0.0.0'
[Microsoft.SqlServer.Dac.DacPackageExtensions]::BuildPackage($path, $model, $meta,
[Microsoft.SqlServer.Dac.PackageOptions]::new())
$model.Dispose()
}
# target project file: header ONE; source: header TWO — the ONLY difference is the header comment
$fileV = "-- header ONE`r`nCREATE PROCEDURE [dbo].[T]`r`nAS`r`nBEGIN`r`n SELECT 1 AS V`r`nEND"
$dbV = "-- header TWO`r`nCREATE PROCEDURE [dbo].[T]`r`nAS`r`nBEGIN`r`n SELECT 1 AS V`r`nEND"
Build-Dacpac "$work\source.dacpac" $dbV
[System.IO.File]::WriteAllText("$work\proj\dbo\StoredProcedures\T.sql", $fileV)
[System.IO.File]::WriteAllText("$work\proj\P.sqlproj",
'<Project DefaultTargets="Build"><Sdk Name="Microsoft.Build.Sql" Version="2.2.0" /><PropertyGroup><Name>P</Name><DSP>Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider</DSP></PropertyGroup></Project>')
$cmp = [Microsoft.SqlServer.Dac.Compare.SchemaComparison]::new(
[Microsoft.SqlServer.Dac.Compare.SchemaCompareDacpacEndpoint]::new("$work\source.dacpac"),
[Microsoft.SqlServer.Dac.Compare.SchemaCompareProjectEndpoint]::new(
"$work\proj\P.sqlproj", [string[]]@("$work\proj\dbo\StoredProcedures\T.sql"),
'Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider',
[Microsoft.SqlServer.Dac.DacExtractTarget]::SchemaObjectType))
$res = $cmp.Compare()
"differences listed : $($res.Differences.Count)"
$before = Get-Content "$work\proj\dbo\StoredProcedures\T.sql" -Raw
$pub = $res.PublishChangesToProject("$work\proj", [Microsoft.SqlServer.Dac.DacExtractTarget]::SchemaObjectType)
$after = Get-Content "$work\proj\dbo\StoredProcedures\T.sql" -Raw
"publish Success : $($pub.Success)"
"changed/added/deleted : $($pub.ChangedFiles.Count)/$($pub.AddedFiles.Count)/$($pub.DeletedFiles.Count)"
"file modified on disk : $($before -cne $after)"
Expected behavior
PublishChangesToProject updates comment-only differences it reported
Impact
Teams using the common SSMS template header (-- Author / Create date / Description above CREATE) get permanent phantom diffs in schema compare that no amount of clicking Apply resolves.
SchemaComparison.Compare()detects differences that exist only in comments (including the conventional header comment block aboveCREATE PROCEDURE), butSchemaComparisonResult.PublishChangesToProject()generates an empty update plan for them and still reportsSuccess = truewith zero changed files. Additionally, even when a module has a real body change, the file update rewrites only the statement body — the header comment aboveCREATEin the project file is never updated from the source.The two layers disagree about what an object is: the comparison layer diffs the full source text (header included), while the update planner works on the semantic model where the header lives only in the
SysCommentsObjectAnnotation(HeaderContents,CreateOffset) and is not actionable. The result is differences that are shown to the user but can never be applied.dacpac→database carries headers along with real changes, while database→project never does.
Steps to Reproduce:
Expected behavior
PublishChangesToProjectupdates comment-only differences it reportedImpact
Teams using the common SSMS template header (
-- Author / Create date / DescriptionaboveCREATE) get permanent phantom diffs in schema compare that no amount of clicking Apply resolves.