Skip to content

SchemaComparison reports comment differences that PublishChangesToProject silently ignores — header comments above CREATE never sync to project files #817

Description

@m0a0k0s
  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions