LocalDB v14 erstellt einen falschen Pfad für MDF-Dateien

34

Kürzlich habe ich LocalDB mit dem SQL Server Express-Installationsprogramm und dieser Anleitung von Version 13 auf Version 14 aktualisiert . Nach der Installation habe ich die vorhandene Standardinstanz (MSSQLLOCALDB) von Version 13 gestoppt und eine neue erstellt, die automatisch die Server-Engine der Version 14.0.1000 verwendet.

Ich verwende LocalDB häufig für Datenbankintegrationstests, dh ich erstelle in meinen xunit-Tests eine (temporäre) Datenbank, die nach Abschluss des Tests gelöscht wird. Seit der neuen Version schlagen leider alle meine Tests wegen folgender Fehlermeldung fehl:

Beim Versuch, die physische Datei "C: \ Users \ kepflDBd0811493e18b46febf980ffb8029482a.mdf" zu öffnen oder zu erstellen, ist beim Erstellen einer Datei der Betriebssystemfehler 5 aufgetreten (Zugriff verweigert.)

Das Seltsame ist, dass der Zielpfad für die MDF-Datei falsch ist und ein Backslash zwischen C: \ Users \ kepfl und DBd0811493e18b46febf980ffb8029482a.mdf fehlt (das ist der zufällige Datenbankname für einen einzelnen Test). Die Datenbanken werden über den einfachen Befehl erstellt CREATE DATABASE [databaseName]- hier nichts Besonderes.

In SSMS werden die folgenden Zielspeicherorte für Daten, Protokoll und Sicherung angezeigt:

LocalDB-Zielspeicherorte

Wenn ich jedoch versuche, den Speicherort zu aktualisieren, wird eine andere Fehlermeldung angezeigt:

Fehlermeldung beim Aktualisieren

Wie kann ich die Standardspeicherorte aktualisieren, damit LocalDB erneut Datenbanken erstellen kann? Es ist offensichtlich, dass LocalDB das Standardverzeichnis und den Namen der Datenbankdatei nicht korrekt kombiniert. Gibt es einen Registrierungseintrag, den ich bearbeiten kann? Oder sonst noch etwas?

Update nach Dougs Antwort und Sepupics Kommentar

Gemäß dieser Stackoverflow-Frage sollten die Standardspeicherorte auch über die Registrierung änderbar sein. Wenn ich jedoch versuche, die entsprechenden Schlüssel "DefaultData", "DefaultLog" und "BackupDirectory" zu finden, kann ich sie nicht in meiner Registrierung finden. Hat SQL Server v14 diese Registrierungsschlüssel umbenannt oder diese Informationen aus der Registrierung entfernt?

feO2x
quelle
Außerdem kann ich die Standardspeicherorte der Datenbank nicht aktualisieren, wenn SSMS im Administratormodus ausgeführt wird.
feO2x
1
Bitte beachten Sie das Update in meiner Antwort. Dieser Bug wurde ab CU6 behoben und Mitte April veröffentlicht.
Solomon Rutzky

Antworten:

21

AKTUALISIEREN

Ab CU 6 für SQL Server 2017 wurde dieser Fehler behoben. Es ist nun möglich, Folgendes erfolgreich auszuführen:

CREATE DATABASE [CreateDatabaseTest];
DROP DATABASE [CreateDatabaseTest];

Das Problem und die Tatsache, dass es in CU6 behoben wurde, sind im folgenden KB-Artikel dokumentiert:
UPDATE: Fehler "Zugriff verweigert" beim Versuch, eine Datenbank in SQL Server 2017 Express LocalDB zu erstellen

Um das kumulative Update zu erhalten, rufen Sie die folgende Seite auf und greifen Sie auf den neuesten Build zu, der möglicherweise neuer als CU6 ist. Dies hängt davon ab, wann Sie dies sehen:

SQL Server 2017-Buildversionen


UNTEN INFO OBSOLETE AB SQL SERVER 2017 CU6 (Veröffentlicht am 17.04.2018)

Das Fehlen eines Backslashs im kombinierten Pfad + Dateinamen scheint ein Fehler in SQL Server 2017 zu sein. Ich bin selbst darauf gestoßen. Ich habe sogar versucht, die Registrierung so zu bearbeiten, dass ein DefaultDataZeichenfolgenwert für C: \ Users \ MyAccountName \ in beiden folgenden Schlüsseln hinzugefügt wird (die drei Standardpfade befinden sich in keinem der von mir durchsuchten LocalDB-Registrierungsschlüssel):

  • Computer \ HKEY_CURRENT_USER \ Software \ Microsoft \ Microsoft SQL Server \ UserInstances \ {irgendein-GUID-Wert}
  • Computer \ HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Microsoft SQL Server \ MSSQL14E.LOCALDB \ MSSQLServer

Und ja, ich habe die LocalDB-Instanz in beiden Versuchen heruntergefahren und neu gestartet.

Ich bin jedoch nicht davon überzeugt, dass es ein Fehler ist, die Standardpfade nicht ändern zu können, da dies möglicherweise nur zu einer schlechten Dokumentation und einer schlechten Fehlerbehandlung führt. Ich sage das, weil ich gerade versucht habe, die Standardspeicherorte für die SQL Server LocalDB-Versionen 2014, 2016 und 2017 zu bearbeiten, und alle genau den gleichen Fehler ergeben haben, der an sich seltsam ist, weil er von stammt RegCreateKeyEx(), der sich mit der Registrierung und befassen sollte nicht das Dateisystem.

Es ist bedauerlich, den Pfad nicht ändern zu können, da beim Erstellen einer neuen Datenbank kein Backslash auftritt, ohne die zu verwendenden Dateien anzugeben. Ich konnte jedoch eine neue Datenbank mit der folgenden vollständigen CREATE DATABASESyntax erstellen :

CREATE DATABASE [XXXXX]
 CONTAINMENT = NONE
 ON PRIMARY 
( NAME = N'XXXXX_sys', FILENAME = N'C:\Users\MyAccountName\XXXXX_sys.mdf',
  SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB ), 
 FILEGROUP [Tables] DEFAULT
( NAME = N'XXXXX_data', FILENAME = N'C:\Users\MyAccountName\XXXXX_data.ndf',
  SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
 LOG ON 
( NAME = N'XXXXX_log', FILENAME = N'C:\Users\MyAccountName\XXXXX_log.ldf',
  SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
 COLLATE Latin1_General_100_CS_AS_KS_WS_SC;
GO
Solomon Rutzky
quelle
In unserem Datenbank-Setup gehen wir davon aus, dass wir, wenn es sich um eine LocalDb-Verbindung handelt, den Pfad der MDF-Datei genau wie in Ihrer Problemumgehung angeben. Es scheint jedoch nicht erforderlich zu sein, auch den Namen des LDF oder den LOG ONAbschnitt der CREATE DATABASEAnweisung anzugeben . Die LDF-Dateien werden anscheinend standardmäßig am selben Speicherort wie die MDF-Datei erstellt. (Unser Anwendungsfall von LocalDb ist hauptsächlich für automatisierte Tests
gedacht
@tgharold Bitte beachten Sie das Update oben in meiner Antwort. Dieser Fehler wurde kürzlich im neuen CU6-Patch behoben :-).
Solomon Rutzky
5

Ich bin auf dasselbe Problem gestoßen und habe eine Problemumgehung gefunden, die keine eindeutigen Nachteile haben sollte (wenn ich etwas vergesse, korrigieren Sie mich bitte) . Es basiert auf der Antwort von Solomons, ohne dass der absolute Pfad zu den Datenbankdateien direkt angegeben werden muss.

DECLARE @databaseName NVARCHAR(MAX) = 'MyDatabase'

DECLARE @dataFilePath NVARCHAR(MAX) = CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS NVARCHAR) 
    + FORMATMESSAGE('\%s.mdf', @databaseName)

DECLARE @sql NVARCHAR(MAX) = FORMATMESSAGE(
    'CREATE DATABASE %s ON PRIMARY ( NAME = %s, FILENAME = ''%s'' )', 
    quotename(@databaseName), quotename(@databaseName), @dataFilePath
)

EXEC (@sql)

Es verwendet dynamisches SQL und ist nicht gerade hübsch, aber es erledigt den Job, bis es eine offizielle Lösung für das Problem gibt.

Nikolaj Dam Larsen
quelle
1
Interessant. Es könnte besser sein , etwas das zweite zu bewegen , QUOTENAMEum den zweiten param von FORMATMESSAGEund setzen doppelte Anführungszeichen um den Dateipfad: FORMATMESSAGE(N'CREATE DATABASE %s ON PRIMARY ( NAME = %s, FILENAME = "%s" )', QUOTENAME(@databaseName), QUOTENAME(@databaseName), @dataFilePath);. Aber es scheint so zu funktionieren, wie Sie es jetzt haben, also +1 für diesen Ansatz. Es gibt immer noch einen Fall, in dem der Name entweder fest codiert oder ein Pfad übergeben wird: Wenn Sie den USERPROFILEStamm nicht verwenden möchten . Aber Sie könnten das hier zulassen und standardmäßig InstanceDefaultDataPathif verwenden @Path IS NULL. :-)
Solomon Rutzky
Vielen Dank. Ich habe die Antwort mit Ihrem Vorschlag bearbeitet. Ich bin damit einverstanden, dass die Hardcodierung des absoluten Pfades definitiv noch eine gültige Lösung ist. In unserem Szenario wurde die Datenbank jedoch nur während automatischer Tests neu erstellt, und ich musste sicherstellen, dass sie für alle meine Kollegen und Buildserver funktioniert, ohne dass jeder koordinieren muss, der auf seinem lokalen Computer einen Ordner mit genau demselben Pfad erstellt. :-)
Nikolaj Dam Larsen
4

Ich stehe auch diesem Problem gegenüber. Die einzige Problemumgehung, die ich gefunden habe, wäre c:\Users\, jedem (oder so ähnlichem) Schreibzugriff zu gewähren und die MDF-Dateien erstellen zu lassen, wo immer sie möchten.

abatishchev
quelle
1
Danke, das hat es auch für mich gelöst! Diese Problemumgehung ist zum Kotzen, aber nur auf unserem lokalen Build-Server. Daher interessieren mich die zusätzlichen Benutzerrechte nicht.
Hannes Sachsenhofer
@HannesSachsenhofer: Ich stimme zu, es ist scheiße. Das LocalDB-Entwicklerteam hat mir jedoch versprochen, diesen Fehler in der kommenden Hotfix-Version zu beheben.
Abatischtschew
Das Gewähren eines Schreibzugriffs für alle scheint mir eine ziemlich schlechte Lösung zu sein
Raphael
@ Raffael: Warum? Sie haben mehrere Benutzer auf Ihrer Dev-Box? Und wem traust du nicht?
abatishchev
2

Vielen Dank für Ihre kurze Erklärung dieses Problems. Ich bin gestern auf dasselbe Problem gestoßen. Ich habe noch keine dauerhafte Lösung gefunden, aber hier ist meine aktuelle Problemumgehung.

Ich benutze die Database.EnsureCreated () - Funktion, um die Datenbank zu erstellen.

Stellen Sie die Verbindungszeichenfolge so ein, dass sie die Einstellung ' AttachDBFilename = ' enthält.

Server=(LocalDB)\\MSSQLLocalDB;Database=ExploreCalifornia;AttachDbFilename=.\\ExploreCalifornia.mdf;Trusted_Connection=True;MultipleActiveResultSets=true

Führen Sie die Anwendung aus. Es wird ein Fehler generiert:

Die Datei '. \ ExploreCalifornia.mdf' kann nicht als Datenbank 'ExploreCalifornia' angehängt werden.

aber es wird die Datenbank erstellen.

Ändern Sie danach die Verbindungszeichenfolge und entfernen Sie ' AttachDBFilename = '.

 Server=(localdb)\\MSSQLLocalDB;Database=ExploreCalifornia;Trusted_Connection=True;MultipleActiveResultSets=true

Ich habe die Anwendung erneut ohne Fehler ausgeführt und Tabellen wurden erstellt.

Doug Abrahamson
quelle
Ein paar Fragen: Erstens, nur um sicherzugehen, dass Sie anfangs einen Fehler (Zugriff verweigert) erhalten haben, der das behebt, richtig? Zweitens: SQL Server Management Studio ist die einzige Anwendung, die von der IP erwähnt wird, und das hört sich nicht nach etwas an, das Sie von dort aus getan haben. Von welcher Anwendung aus haben Sie all dies getan?
RDFozz
Danke für deine Antwort, aber das löst mein Problem nicht wirklich. Mein CREATE DATABASE [databasename]Testcode erstellt eine neue Datenbank mit einer einfachen gegen LocalDB und diese Anweisung verursacht Probleme, da LocalDB das Standardverzeichnis mit dem zufällig generierten Datenbanknamen fälschlicherweise verkettet (siehe Absätze 3 und 4 meiner Frage). Ich brauche eine Möglichkeit, die Standardspeicherorte zu beheben, damit dieses Verkettungsproblem nicht auftritt.
feO2x
Derzeit kann ich überhaupt keine Datenbank über SQL / DDL erstellen. Es spielt keine Rolle, ob ich die Anweisung über SSMS oder über Code oder irgendwo anders ausführe, da LocalDB immer versucht, die Datenbank direkt im Benutzerverzeichnis zu erstellen (was völlig falsch ist, in diesem Verzeichnis dürfen keine Dateien existieren). .
feO2x
1
Sie haben möglicherweise falsch geschrieben AttachDBFilename.
Tgharold