LocalDB v14为mdf文件创建错误的路径


34

最近,我使用SQL Server Express安装程序和此指令将LocalDB从版本13升级到了版本14。。安装后,我停止了版本13的现有默认实例(MSSQLLOCALDB)并创建了一个新实例,该实例自动使用v14.0.1000服务器引擎。

我经常使用LocalDB进行数据库集成测试,即在我的xunit测试中,我创建一个(临时)数据库,该数据库在测试完成时将被删除。从新版本开始,很遗憾,由于以下错误消息,我的所有测试均失败:

尝试打开或创建物理文件'C:\ Users \ kepflDBd0811493e18b46febf980ffb8029482a.mdf'时,CREATE FILE遇到操作系统错误5(访问被拒绝。)

奇怪的是,mdf文件的目标路径不正确,C:\ Users \ kepflDBd0811493e18b46febf980ffb8029482a.mdf(这是单个测试的随机数据库名称)之间缺少反斜杠。通过简单的命令创建数据库CREATE DATABASE [databaseName]-这里没有什么特别的。

在SSMS中,我看到数据,日志和备份的目标位置如下:

LocalDB目标位置

但是,当我尝试更新位置时,出现另一条错误消息:

尝试更新时出现错误信息

如何更新默认位置,以便LocalDB能够再次创建数据库?很明显,LocalDB没有正确组合默认位置目录和数据库文件名-是否有我可以编辑的注册表项?还是其他?

在道格的回答和坟墓的评论后更新

根据这个Stackoverflow问题,默认位置也应该可以通过注册表更改。但是,如果我尝试找到相应的键“ DefaultData”,“ DefaultLog”和“ BackupDirectory”,则无法在注册表中找到它们。SQL Server v14是否重命名了这些注册表项,还是将这些信息移出了注册表?


仅供参考,在管理员模式下运行SSMS时,我也无法更新数据库默认位置。
feO2x

1
请在我的答案中查看更新。此错误已从CU6(已于4月中旬发布)中修复。.–
所罗门·

Answers:


21

更新

从SQL Server 2017 CU 6开始,此错误已修复。现在可以成功执行以下操作:

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

下面的知识库文章中记录了该问题及其在CU6中已修复的事实
:当您尝试在SQL Server 2017 Express LocalDB中创建数据库时,FIX:“访问被拒绝”错误

要获得累积更新,请转到以下页面并获取顶级(即最新)版本,具体取决于您何时看到,它可能比CU6更新:

SQL Server 2017内部版本


低于SQL Server 2017 CU6的信息过时(于2018-04-17发行)

组合的路径+文件名中缺少反斜杠似乎是SQL Server 2017的一个错误。我自己碰到了它。我什至尝试编辑注册表以在以下两个键中添加C:\ Users \ MyAccountName \DefaultData字符串值(3个默认路径不在我浏览过的任何LocalDB注册表键中):

  • Computer \ HKEY_CURRENT_USER \ Software \ Microsoft \ Microsoft SQL Server \ UserInstances \ {some-GUID-value}
  • 计算机\ HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Microsoft SQL Server \ MSSQL14E.LOCALDB \ MSSQLServer

是的,在两次尝试中,我都关闭并重新启动了LocalDB实例。

但是,我不相信不能更改默认路径是一个错误,因为它可能是糟糕的文档和错误处理的总和。我之所以这样说是因为我刚刚尝试编辑SQL Server LocalDB版本2014、2016和2017的默认位置,并且都导致了完全相同的错误,由于来自from RegCreateKeyEx(),这本身是奇怪的,应该与Registry和不是文件系统。

不幸的是,由于在创建新数据库而不指定要使用的文件时缺少反斜杠,因此无法更改路径。但是,我能够使用CREATE DATABASE如下完整语法创建一个新的数据库:

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

我们在数据库设置中采用的方法是,如果它是LocalDb连接,则指定MDF文件的路径,就像您的解决方法一样。但是似乎也不必指定LDF的名称或语句的LOG ON部分CREATE DATABASE。默认情况下,似乎在与MDF文件相同的位置创建了LDF文件。(我们的LocalDb用例主要用于自动化测试。)
tgharold

@tgharold请在我的答案顶部查看更新。这个错误是最近在新的CU6补丁中修复的:-)。
所罗门·鲁兹基

5

我遇到了同样的问题,发现了一种应该没有明显缺点的变通方法(如果我忘记了什么,请纠正我)。它基于Solomons的答案,但无需直接指定数据库文件的绝对路径。

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)

它使用动态sql并不太漂亮,但是可以完成工作,直到对该问题进行正式修复为止。


1
有趣。这可能会稍微好一点移动的第2 QUOTENAME到第2 PARAM FORMATMESSAGE,并把周围的文件路径双引号:FORMATMESSAGE(N'CREATE DATABASE %s ON PRIMARY ( NAME = %s, FILENAME = "%s" )', QUOTENAME(@databaseName), QUOTENAME(@databaseName), @dataFilePath);。但它似乎可以像您现在所拥有的那样工作,因此请为此方法+1。仍然存在对名称进行硬编码或传递路径的情况:当您不想使用USERPROFILE根时。但是您可以在这里允许,并且默认为InstanceDefaultDataPathif @Path IS NULL。:-)
所罗门·鲁兹基

谢谢。我已经根据您的建议编辑了答案。我同意硬编码绝对路径绝对仍然是有效的解决方案。但是在我们的场景中,我们仅在自动测试期间重新创建数据库,而我必须确保该数据库适用于所有同事和构建服务器,而不必协调每个人在其本地计算机上的完全相同的路径上创建文件夹。:-)
Nikolaj Dam Larsen

4

我也面临这个问题。我发现的唯一解决方法是将写入权限授予c:\Users\所有人(或类似的东西),并让它在任何需要的地方创建mdf文件。


1
谢谢,这也为我解决了!这种解决方法很糟糕,但是它仅在我们的本地构建服务器上,因此我不在乎其他用户权限。
Hannes Sachsenhofer

@HannesSachsenhofer:我同意,这很糟糕。但是LocalDB开发团队向我保证,他们将在即将发布的修补程序版本中修复此错误。
abatishchev

授予所有人访问权限的权限对我来说似乎是一个非常糟糕的解决方法
Raphael

@Raphael:为什么?您的开发箱中有多个用户?而你不信任谁?
abatishchev

2

感谢您对此问题的简要说明。我昨天也遇到了同样的问题。我仍然没有找到永久的解决方案,但这是我当前的解决方法。

我正在使用Database.EnsureCreated()函数创建数据库。

将连接字符串设置为包括“ AttachDBFilename = ”设置。

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

运行应用程序。它将产生一个错误:

无法将文件“。\ ExploreCalifornia.mdf”附加为数据库“ ExploreCalifornia”。

但是它将创建数据库。

之后,更改连接字符串并删除' AttachDBFilename = '。

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

我再次运行该应用程序,没有错误,并创建了表。


有两个问题:首先,可以肯定的是-您最初遇到(访问被拒绝)错误,并且此操作可以解决此问题,对吗?其次-SQL Server Management Studio是IP提及的唯一应用程序,这听起来不像您从那里所做的事情-您是从哪个应用程序执行这些操作的?
RDFozz

感谢您的回答,但这并不能真正解决我的问题。我的测试代码使用一个CREATE DATABASE [databasename]针对LocalDB 的简单代码创建了一个新数据库,由于LocalDB错误地将默认的locations目录与随机生成的数据库名称连接在一起(参见我的问题的第3和第4段),因此这一声明引起了问题。我需要一种方法来修复默认位置,以便不会发生此串联问题。
feO2x

目前,我根本无法通过SQL / DDL创建数据库。不管是通过SSMS还是从代码或其他任何地方运行该语句都没有关系,因为LocalDB总是尝试直接在Users目录中直接创建数据库(这是完全错误的,该目录中不允许存在文件) 。
feO2x

1
您可能拼错了AttachDBFilename
tgharold
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.