我有一个Windows C#WPF客户端应用程序,我使用EF来访问LocalDB实例(当然这将是一个真正的SQL Server数据库)。此应用程序使用数据库来保留某些配置。最初由EF使用CreateDatabaseIfNotExists初始化程序创建数据库。
然后在启动时自动运行具有本地系统权限的Windows服务。此服务仅在启动时访问数据库,以使用以下代码获取一个特定配置值(从示例代码中删除异常处理,无法使用EF):
using (SqlConnection connection = new SqlConnection
{
ConnectionString = $"Data Source =(LocalDB)\\MSSQLLocalDB;AttachDbFilename=D:\database.mdf;Integrated Security=True;Connect Timeout=30",
})
{
connection.Open();
string query = "SELECT TOP 1 COLUMN_1 FROM TABLE_1;";
using (SqlCommand command = new SqlCommand(query, connection))
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
if (!reader.IsDBNull(0))
{
value = reader.GetString(0);
}
}
}
}
我已多次测试此代码段并在f.e处设置调试断点。 while循环但客户端应用程序总是可以启动并且没有创建数据库的问题(因为它已经存在)。
问题是"它适用于我的机器"并不满足测试人员,因为他们有时会遇到错误,重启后无法再创建数据库。这是异常堆栈跟踪:
System.Data.SqlClient.SqlException(0x80131904):无法创建文件' D:\ database.mdf'因为它已经存在更改文件路径或文件名,然后重试该操作。 CREATE DATABASE失败。无法创建列出的某些文件名。检查相关错误。 在System.Data.SqlClient.SqlConnection.OnError(SqlException异常,Boolean breakConnection,Action wrapCloseInAction) 在System.Data.SqlClient.SqlInternalConnection.OnError(SqlException异常,Boolean breakConnection,Action wrapCloseInAction) 在System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,Boolean callerHasConnectionLock,Boolean asyncClose) 在System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand cmdHandler,SqlDataReader dataStream,BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject stateObj,Boolean& dataReady) 在System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName,Boolean async,Int32 timeout,Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource completion,String methodName,Boolean sendToPipe,Int32 timeout,Boolean asyncWrite) 在System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 在System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.b__0(DbCommand t,DbCommandInterceptionContext c) at System.Data.Entity.Infrastructure.Interception.InternalDispatcher.Dispatch [TTarget,TInterceptionContext,TResult](TTarget target,Func operation,TInterceptionContext interceptionContext,Action execution,Action execution) 在System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand命令,DbCommandInterceptionContext interceptionContext) 在System.Data.Entity.SqlServer.SqlProviderServices。<> c__DisplayClass1a.b__19(DbConnection conn) 在System.Data.Entity.SqlServer.SqlProviderServices。<> c__DisplayClass33.b__32() 在System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy。<> c__DisplayClass1.b__0() 在System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute [TResult](Func操作) 在System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action操作) 在System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnection sqlConnection,Action act) 在System.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(DbConnection sqlConnection,Action act) 在System.Data.Entity.SqlServer.SqlProviderServices.CreateDatabaseFromScript(Nullable commandTimeout,DbConnection sqlConnection,String createDatabaseScript) 在System.Data.Entity.SqlServer.SqlProviderServices.DbCreateDatabase(DbConnection连接,Nullable commandTimeout,StoreItemCollection storeItemCollection) 在System.Data.Entity.Core.Common.DbProviderServices.CreateDatabase(DbConnection连接,Nullable commandTimeout,StoreItemCollection storeItemCollection) 在System.Data.Entity.Core.Objects.ObjectContext.CreateDatabase() at System.Data.Entity.Internal.DatabaseOperations.Create(ObjectContext objectContext) 在System.Data.Entity.Internal.DatabaseCreator.CreateDatabase(InternalContext internalContext,Func createMigrator,ObjectContext objectContext) 在System.Data.Entity.Internal.InternalContext.CreateDatabase(ObjectContext objectContext,DatabaseExistenceState existState) 在System.Data.Entity.Database.Create(DatabaseExistenceState existState) at System.Data.Entity.CreateDatabaseIfNotExists.InitializeDatabase(TContext context) 在System.Data.Entity.Internal.InternalContext。<> c__DisplayClassf`1.b__e() 在System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action) 在System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization() 在System.Data.Entity.Internal.LazyInternalContext.b__4(InternalContext c) 在System.Data.Entity.Internal.RetryAction.PerformAction(TInput输入) 在System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action action) 在System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase() 在System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) 在System.Data.Entity.Internal.Linq.InternalSet.Initialize() 在System.Data.Entity.Internal.Linq.InternalSet.get_InternalContext() 在System.Data.Entity.Infrastructure.DbQuery.System.Linq.IQueryable.get_Provider() bei System.Linq.Queryable.Count [TSource](IQueryable source) bei MyProgram.DatabaseService.Initialize()
我无法解释自己出了什么问题。
可能存在模型不匹配或竞争条件,但我无法让方案重现此错误,说实话,错误消息看起来很简单。
修改
使用procmon检查文件句柄后,您可以看到服务"阻止"数据库文件,只要它使用它加上一些额外的时间(也许SQLLocalDB本身需要这个时间)。 此时没有其他用户可以访问数据库。我尝试使用作为同一用户运行的客户端和服务,然后两者都可以同时访问该文件。怎么会这样?