We use Azure SQL databases in production and in our test environments, but for our integration tests, we use LocalDB by deploying a DACPAC to LocalDB and backing it up for reuse. The problem is that there are edge cases that are not caught due to differences between Azure SQL databases and LocalDB databases, particularly around collation.
We had a column in a table with a custom collation. With the wrong Entity Framework (EF) configuration, this didn’t work in Azure but worked in our integration tests. You do not want integration tests that work differently than production for obvious reasons. The solution was to set the LocalDB to Containment Partial. This way, collation is handled entirely by the database instance, and no fallback to default server collation will occur.
The code in our case:
public static async Task InitBackup(string systemName, IEnumerable<KeyValuePair<string, string>>? sqlCommandVariableValues = null)
{
_systemName = systemName;
var dacPackPath = GetDacPackPath();
var dacMd5 = DacPacFingerprint(dacPackPath);
_backup = $"{SystemName}_{dacMd5}.bak";
try
{
SetBackupInfo();
}
catch (SqlException)
{
var backupFile = GetUserProfilePath(_backup);
if (File.Exists(backupFile)) File.Delete(backupFile);
var instance = new DacServices(string.Format(ConnectionStringTemplate, "master"));
var options = new DacDeployOptions();
sqlCommandVariableValues?.ForEach(kvp => options.SqlCommandVariableValues.Add(kvp.Key, kvp.Value));
var tempDb = $"dacpac_{SystemName}_{Guid.NewGuid().ToString().Replace("-", "_")}";
using (var dacPak = DacPackage.Load(dacPackPath))
instance.Deploy(dacPak, tempDb, false, options);
await ExecuteASync("sp_configure 'contained database authentication', 1;RECONFIGURE;");
await ExecuteASync($"ALTER DATABASE [{tempDb}] SET CONTAINMENT = PARTIAL WITH NO_WAIT");
var sql = $@"BACKUP DATABASE {tempDb}
TO DISK = '{_backup}'";
await ExecuteASync(sql);
SetBackupInfo();
_ = Task.Run(() => Kill(tempDb));
}
}
The important part is enabling contained authentication, which is required for partial containment, and then enabling partial containment for the database.

