【发布时间】:2023-04-09 14:20:01
【问题描述】:
目前我正在尝试使用实体框架 6 的代码优先方法在 SQL Express 2012 实例上创建/连接到不同的数据库。需要在代码中创建到数据库的连接字符串,如果数据库不存在,则应在 SQL Express 实例上创建它。以下是我的班级结构:
public class TestContext : DbContext
{
public TestContext()
{}
public TestContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<TestContext, Configuration>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ChildItem>().HasRequired(s => s.Parent)
.WithMany(s => s.ChildItems);
base.OnModelCreating(modelBuilder);
}
public DbSet<ParentItem> Parents { get; set; }
public DbSet<ChildItem> Childs { get; set; }
}
[Table("Parents")]
public class ParentItem
{
public ParentItem()
{
Childs = new List<ChildItem>();
}
[Key]
public int ParentId {get; set;}
public string ParentName { get; set; }
public virtual List<ChildItem> Childs { get; set; }
}
[Table("Childs")]
public class ChildItem
{
[Key]
public int ChildId { get; set; }
public string Name { get; set; }
public virtual ParentItem Parent { get; set; }
}
当我现在尝试为新数据库添加数据或向现有数据库添加数据时,我收到以下异常。
> System.Data.DataException was unhandled by user code
> HResult=-2146233087 Message=An exception occurred while initializing
> the database. See the InnerException for details.
> Source=EntityFramework StackTrace:
> at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action
> action)
> at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()
> at System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext
> c)
> at System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input)
> at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1
> action)
> at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase()
> at System.Data.Entity.Internal.InternalContext.Initialize()
> at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type
> entityType)
> at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
> at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
> at System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action,
> EntityState newState, Object entity, String methodName)
> at System.Data.Entity.Internal.Linq.InternalSet`1.Add(Object entity)
> at System.Data.Entity.DbSet`1.Add(TEntity entity)
> at UnitTestProject.TestContextTest.InsertManyMeasurmentsDirectlyWithSql()
> in MSSQLTest.cs:line 123 InnerException:
> System.Data.Entity.Core.ProviderIncompatibleException
> HResult=-2146233087
> Message=An error occurred while getting provider information from the database. This can be caused by Entity Framework using an
> incorrect connection string. Check the inner exceptions for details
> and ensure that the connection string is correct.
> Source=EntityFramework
> StackTrace:
> at System.Data.Entity.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices
> providerServices, DbConnection connection)
> at System.Data.Entity.Infrastructure.DefaultManifestTokenResolver.<>c__DisplayClass1.<ResolveManifestToken>b__0(Tuple`3
> k)
> at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey
> key, Func`2 valueFactory)
> at System.Data.Entity.Infrastructure.DefaultManifestTokenResolver.ResolveManifestToken(DbConnection
> connection)
> at System.Data.Entity.Utilities.DbConnectionExtensions.GetProviderInfo(DbConnection
> connection, DbProviderManifest& providerManifest)
> at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
> at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext
> context, XmlWriter writer)
> at System.Data.Entity.Utilities.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter
> w)
> at System.Data.Entity.Utilities.DbContextExtensions.GetModel(Action`1
> writeXml)
> at System.Data.Entity.Utilities.DbContextExtensions.GetModel(DbContext
> context)
> at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration
> configuration, DbContext usersContext)
> at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration
> configuration)
> at System.Data.Entity.MigrateDatabaseToLatestVersion`2.InitializeDatabase(TContext
> context)
> at System.Data.Entity.Internal.InternalContext.<>c__DisplayClasse`1.<CreateInitializationAction>b__d()
> at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action
> action)
> InnerException: System.Data.Entity.Core.ProviderIncompatibleException
> HResult=-2146233087
> Message=The provider did not return a ProviderManifestToken string.
> Source=EntityFramework
> StackTrace:
> at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection
> connection)
> at System.Data.Entity.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices
> providerServices, DbConnection connection)
> InnerException: System.Data.SqlClient.SqlException
> HResult=-2146232060
> Message=A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was
> not found or was not accessible. Verify that the instance name is
> correct and that SQL Server is configured to allow remote connections.
> (provider: SQL Network Interfaces, error: 26 - Error Locating
> Server/Instance Specified)
> Source=.Net SqlClient Data Provider
> ErrorCode=-2146232060
> Class=20
> LineNumber=0
> Number=-1
> Server=""
> State=0
> StackTrace:
> at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
> exception, Boolean breakConnection, Action`1 wrapCloseInAction)
> at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject
> stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
> at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo,
> SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout,
> Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean
> integratedSecurity, Boolean withFailover)
> at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo
> serverInfo, String newPassword, SecureString newSecurePassword,
> Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean
> withFailover)
> at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo
> serverInfo, String newPassword, SecureString newSecurePassword,
> Boolean redirectedUserInstance, SqlConnectionString connectionOptions,
> SqlCredential credential, TimeoutTimer timeout)
> at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer
> timeout, SqlConnectionString connectionOptions, SqlCredential
> credential, String newPassword, SecureString newSecurePassword,
> Boolean redirectedUserInstance)
> at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity
> identity, SqlConnectionString connectionOptions, SqlCredential
> credential, Object providerInfo, String newPassword, SecureString
> newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString
> userConnectionOptions, SessionData reconnectSessionData)
> at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions
> options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo,
> DbConnectionPool pool, DbConnection owningConnection,
> DbConnectionOptions userOptions)
> at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool
> pool, DbConnection owningObject, DbConnectionOptions options,
> DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
> at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection
> owningObject, DbConnectionOptions userOptions, DbConnectionInternal
> oldConnection)
> at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection
> owningObject, DbConnectionOptions userOptions, DbConnectionInternal
> oldConnection)
> at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection
> owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean
> allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions
> userOptions, DbConnectionInternal& connection)
> at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection
> owningObject, TaskCompletionSource`1 retry, DbConnectionOptions
> userOptions, DbConnectionInternal& connection)
> at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection
> owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions
> userOptions, DbConnectionInternal oldConnection, DbConnectionInternal&
> connection)
> at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection
> outerConnection, DbConnectionFactory connectionFactory,
> TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
> at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection
> outerConnection, DbConnectionFactory connectionFactory,
> TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
> at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1
> retry)
> at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1
> retry)
> at System.Data.SqlClient.SqlConnection.Open()
> at System.Data.Entity.SqlServer.SqlProviderServices.<>c__DisplayClass2f.<UsingConnection>b__2d()
> at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
> at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1
> operation)
> at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action
> operation)
> at System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnection
> sqlConnection, Action`1 act)
> at System.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(DbConnection
> sqlConnection, Action`1 act)
> at System.Data.Entity.SqlServer.SqlProviderServices.GetDbProviderManifestToken(DbConnection
> connection)
> at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection
> connection)
> InnerException:
我发现这是因为 TestContext.Parents.Add(..) 调用了我的 TestContext 的默认构造函数,而没有调用基本构造函数。我找到了一个非常肮脏的解决方法,如下所示。
public class TestContext : DbContext
{
private static string dbname = "TestDB";
public TestContext() : base(dbname)
{
}
public TestContext(string connectionString)
: base(connectionString)
{
dbname = connectionString;
Database.SetInitializer(new MigrateDatabaseToLatestVersion<TestContext, Configuration>());
}
在此之后一切正常,但我不喜欢这种解决方案。特别是当我将使用支持多个数据库的多个线程时,我会遇到静态变量的问题。 如果已经尝试过以下站点的解决方案,但没有任何效果。
- Entity Framework code first custom connection string and migrations
- Changing connection string at runtime
那么还有其他人建议如何解决这个问题吗?
--- 编辑:24.03 ----
进一步调查表明,所描述的问题和默认构造函数的第二次调用仅在启用迁移时发生。
【问题讨论】:
标签: entity-framework ef-code-first sql-server-2012