【问题标题】:Problems with dynamic connection strings in Entity Framework 6 Code FirstEntity Framework 6 Code First 中的动态连接字符串问题
【发布时间】: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>());
        }

在此之后一切正常,但我不喜欢这种解决方案。特别是当我将使用支持多个数据库的多个线程时,我会遇到静态变量的问题。 如果已经尝试过以下站点的解决方案,但没有任何效果。

那么还有其他人建议如何解决这个问题吗?

--- 编辑:24.03 ----

进一步调查表明,所描述的问题和默认构造函数的第二次调用仅在启用迁移时发生。

【问题讨论】:

    标签: entity-framework ef-code-first sql-server-2012


    【解决方案1】:

    我找到了可以接受的解决方案或更好的解决方法。 为了解决这个问题,我使用多个数据库上下文来访问数据库。我将介绍反映完整数据库结构的数据库上下文。对于此数据库上下文,将启用迁移功能。此数据库上下文将用于创建数据库。有了这个限制,我可以使用以下代码来创建第一个数据库。但我需要确保当时只有一个线程创建一个新数据库。

    public class TestContext : DbContext
    {
      private static string connection = "TestDb";
    
      public TestContext() : this(connection)
      {}
    
      public TestContext (string newConnection) : base(connection)
      {
        connection = newConnection;
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<TestContext, Configuration>());
      }
    …
    

    其他数据库上下文仅访问数据库系统的一部分,但将数据库初始化程序设置为 null。有了这个,我可以使用动态字符串访问多个数据库,并且默认构造函数没有问题。我还可以使用不同的线程访问数据库,而不必担心静态变量。

    public class SecondTestContext : DbContext
    {
      public SecondTestContext (string dbName) : base(dbName)
      {
        Database.SetInitializer<SecondTestContext>(null);
      }
    …
    

    【讨论】:

      猜你喜欢
      • 2011-10-24
      • 1970-01-01
      • 2011-05-06
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多