Entity Framework學習筆記——記一個錯誤解決方式及思路


繼續之前設定的學習目標前,先來一篇小小的外篇。按照第一篇里的配置方式配置好的工程前兩天還能正常工作,昨天卻突然無法通過Add-Migration命令進行數據庫的升級。錯誤信息如下:

System.Data.Entity.Core.ProviderIncompatibleException: 從數據庫中獲取提供程序信息時出錯。這可能是 Entity Framework 使用的連接字符串不正確導致的。有關詳細信息,請查看內部異常並確保連接字符串正確。 ---> System.Data.Entity.Core.ProviderIncompatibleException: 提供程序未返回 ProviderManifestToken 字符串。 ---> System.Data.SqlClient.SqlException: 在與 SQL Server 建立連接時出現與網絡相關的或特定於實例的錯誤。未找到或無法訪問服務器。請驗證實例名稱是否正確並且 SQL Server 已配置為允許遠程連接。 (provider: SQL Network Interfaces, error: 26 - 定位指定的服務器/實例時出錯)
   在 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   在 System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity, Boolean withFailover)
   在 System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover)
   在 System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
   在 System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
   在 System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions)
   在 System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   在 System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
   在 System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnectionOptions userOptions)
   在 System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnectionOptions userOptions)
   在 System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   在 System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   在 System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   在 System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   在 System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   在 System.Data.SqlClient.SqlConnection.Open()
   在 System.Data.Entity.SqlServer.SqlProviderServices.<>c__DisplayClass2f.<UsingConnection>b__2d()
   在 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
   在 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   在 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation)
   在 System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnection sqlConnection, Action`1 act)
   在 System.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(DbConnection sqlConnection, Action`1 act)
   在 System.Data.Entity.SqlServer.SqlProviderServices.GetDbProviderManifestToken(DbConnection connection)
   在 System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
   --- 內部異常堆棧跟蹤的結尾 ---
   在 System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
   在 System.Data.Entity.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection)
   --- 內部異常堆棧跟蹤的結尾 ---
   在 System.Data.Entity.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection)
   在 System.Data.Entity.Infrastructure.DefaultManifestTokenResolver.<>c__DisplayClass1.<ResolveManifestToken>b__0(Tuple`3 k)
   在 System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   在 System.Data.Entity.Infrastructure.DefaultManifestTokenResolver.ResolveManifestToken(DbConnection connection)
   在 System.Data.Entity.Utilities.DbConnectionExtensions.GetProviderInfo(DbConnection connection, DbProviderManifest& providerManifest)
   在 System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
   在 System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
   在 System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
   在 System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
   在 System.Data.Entity.Internal.LazyInternalContext.get_ModelBeingInitialized()
   在 System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
   在 System.Data.Entity.Utilities.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter w)
   在 System.Data.Entity.Utilities.DbContextExtensions.GetModel(Action`1 writeXml)
   在 System.Data.Entity.Utilities.DbContextExtensions.GetModel(DbContext context)
   在 System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
   在 System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
   在 System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration)
   在 System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Run()
   在 System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   在 System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   在 System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
   在 System.Data.Entity.Migrations.Design.ToolingFacade.Scaffold(String migrationName, String language, String rootNamespace, Boolean ignoreChanges)
   在 System.Data.Entity.Migrations.AddMigrationCommand.Execute(String name, Boolean force, Boolean ignoreChanges)
   在 System.Data.Entity.Migrations.AddMigrationCommand.<>c__DisplayClass2.<.ctor>b__0()
   在 System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
從數據庫中獲取提供程序信息時出錯。這可能是 Entity Framework 使用的連接字符串不正確導致的。有關詳細信息,請查看內部異常並確保連接字符串正確。
View Code

在網上查了很多相關資料,主要使用ProviderManifestToken作為搜索關鍵字,發現有挺多人遇到了類似問題,可能的原因如下:
1. 數據庫連接字符串配錯了,常見的有數據庫服務器名稱、數據庫名拼寫錯誤。
2. 數據庫連接字符串里的用戶名密碼沒有登錄權限或者密碼過期了了。
3. 數據庫連接字符串配置項的name值與Context的名稱不一致找不到。
4. 數據庫版本是2000,也有說2005也可能有問題的。

逐一排除,首先檢查數據庫連接字符串,因為之前配置完是可以連接和生成數據庫的,數據庫連接字符串應該不會有問題。不過我還是參考了“數據庫連接字符串大全”這篇文章中的連接字符串配置方式檢查了兩遍,結果無效,同樣的配置項,用SMSS可以登錄數據庫,故排除。
其次檢查登錄權限和密碼,因為剛才說過用SMSS可以登錄,因此也可以排除了。
剩下的兩個問題也不存在,因此配置項的問題可能性比較小了。可是數據庫連不上就沒法繼續工作,只能硬着頭皮繼續排查。

先說下我的項目工程和目錄結構:
項 目采用了3層架構的方式,其實對小項目有點累贅和多余,不過為了跟其他項目保持一致,還是這樣設計了。項目是一個WCF服務,主工程名稱為XXX,業務層 工程名稱為XXX.Business,數據庫層為XXX.Db,還有實體等其他的一些工程。現在唯一能想到的辦法就是在項目中編寫最基本的ADO.Net 代碼訪問數據庫,檢查是否是EF自身的問題。由於WCF還未完全配好,暫時不能通過頂級去執行DB層代碼,因此寫了一個單元測試調用DB層,在DB里寫了 一個基本的讀取連接字符串配置項,然后打開數據庫連接的方法。第一次調試單元測試,發現配置項獲取到的連接字符串為null。才想起來我的配置文件在DB 里,單元測試工程中沒有EF的配置項。於是把DB里的連接字符串配置項拷貝到單元測試工程中,連接順利打開。
就是剛才的這一點提醒了我,是不是配置文件位置有問題。最開始用DB工程生成數據庫的時候,可能是把XXX.Db設為了啟動項,后來配置WCF,又把XXX設為了啟動項,莫非是啟動項搞的鬼?變成XXX.Db為啟動項,問題解決。

原來PM中的默認項目不能保證配置文件就從選擇的項目中讀取,小小的問題耗了大半天的時間終於解決了。
在這里向大家分享這個問題,希望能幫到你。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM