diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f22ca69..af8c04e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ Update this document for externally visible changes. Put most recent changes first. Once we push a new version to nuget.org add a double hash header for that version. +- Fix `Database.Owner` returning the previous owner after `Database.SetOwner()` until `Refresh()` was called. The cached property is now invalidated and re-fetched from the server on next access. + ## 181.37.1 - Add `ServerConnection.Edition` and `ServerConnection.EditionID` to expose the values of `SERVERPROPERTY('Edition')` and `SERVERPROPERTY('EditionID')`. diff --git a/src/FunctionalTest/Smo/ScriptingTests/Database_SmoTestSuite.cs b/src/FunctionalTest/Smo/ScriptingTests/Database_SmoTestSuite.cs index e654e4b1..1518d157 100644 --- a/src/FunctionalTest/Smo/ScriptingTests/Database_SmoTestSuite.cs +++ b/src/FunctionalTest/Smo/ScriptingTests/Database_SmoTestSuite.cs @@ -1190,8 +1190,17 @@ public void Database_CanChangeOwner() { database.SetOwner(login.Name); + Assert.That(database.Owner, Is.EqualTo(login.Name), "Owner of database should reflect the new owner immediately after calling SetOwner, without needing Refresh"); database.Refresh(); Assert.That(database.Owner, Is.EqualTo(login.Name), "Owner of database was not changed to '{0}' after calling SetOwner"); + + if (!database.Parent.Information.IsCaseSensitive) + { + //The server resolves the login case-insensitively and keeps its own spelling, + //so Owner has to return the stored name and not the casing passed to SetOwner + database.SetOwner(login.Name.ToUpperInvariant()); + Assert.That(database.Owner, Is.EqualTo(login.Name), "Owner of database should return the login name as stored on the server, not the casing passed to SetOwner"); + } } finally { @@ -1227,6 +1236,7 @@ public void Database_CanChangeOwner_WithExistingUser() try { database.SetOwner(login.Name, dropExistingUser: true); + Assert.That(database.Owner, Is.EqualTo(login.Name), "Owner of database should reflect the new owner immediately after calling SetOwner, without needing Refresh"); database.Refresh(); Assert.That(database.Owner, Is.EqualTo(login.Name), "Owner of database was not changed to '{0}' after calling SetOwner"); } diff --git a/src/Microsoft/SqlServer/Management/Smo/DatabaseBase.cs b/src/Microsoft/SqlServer/Management/Smo/DatabaseBase.cs index ab4edf06..7c04a5f2 100644 --- a/src/Microsoft/SqlServer/Management/Smo/DatabaseBase.cs +++ b/src/Microsoft/SqlServer/Management/Smo/DatabaseBase.cs @@ -1369,6 +1369,18 @@ private void SetOwnerImpl(string loginName, bool dropExistingUser) this.ScriptChangeOwner(query, loginName); this.ExecutionManager.ExecuteNonQuery(query); + + if (!this.ExecutionManager.Recording) + { + //The query only propagates the new owner to the server, so the cached + //Owner value is stale now. Invalidate it so it is retrieved from the + //server on next access. We don't store the caller-provided name because + //the server may canonicalize it differently (e.g. different casing on + //a case-insensitive server). + Property owner = this.Properties.Get("Owner"); + owner.SetRetrieved(false); + this.propertyBagState = PropertyBagState.Lazy; + } } } catch (Exception e)