8

我正在尝试编写一个易于理解的DBContext类,它采用自定义连接字符串,可以运行迁移,并且允许我使用包管理器生成迁移。

我好像在兜圈子。

我已经能够使用对我来说感觉很糟糕的代码让它工作。我在对连接字符串和迁移的这个问题的回答中记录了这一点。

Radek 的答案看起来比我的要好得多,但我发现当我实现它然后尝试在包管理器中创建迁移时,我收到了消息

目标上下文“DataLayer.Context”不可构造。添加默认构造函数或提供 IDbContextFactory 的实现。

DataLayer.Context我的上下文课程在哪里。

我不想提供IDbContextFactory(并且 Radek 的回答似乎表明它不需要)的实现

更新:

如果我包含不带参数的构造函数,我可以生成迁移。例如

public Context() : base("ConnectionStringName") { }

对于我的上下文创建,我在 app.config 中传递了连接字符串的名称

public Context(string connString) : base(connString)
{
    Database.SetInitializer(new CustomInitializer());
    Database.Initialize(true);
}

最后,我既可以生成迁移,也可以为用户选择的数据库运行迁移。

但是:当我删除数据库然后运行我的应用程序时,我遇到了问题。

我正在使用的初始化代码,来自上面的链接是

public class CustomInitializer : IDatabaseInitializer<Context>
{       
    public void InitializeDatabase(Context context)
    {
        try
        {
            if (!context.Database.Exists())
            {
                context.Database.Create();
            }
            else
            {
                if (!context.Database.CompatibleWithModel(false))  
                {
                    var configuration = new Configuration();
                    var migrator = new DbMigrator(configuration);
                    migrator.Configuration.TargetDatabase =
                        new DbConnectionInfo(context.Database.Connection.ConnectionString);
                    IEnumerable<string> migrations = migrator.GetPendingMigrations();
                    foreach (string migration in migrations)
                    {
                        var scriptor = new MigratorScriptingDecorator(migrator);
                        string script = scriptor.ScriptUpdate(null, migration);
                        context.Database.ExecuteSqlCommand(script);
                    }
                }
            }
        }
        catch (Exception ex)
        {
        }
    }       
}

当我删除数据库时,会创建一个新数据库,但它没有表。那是因为我的表创建代码都在我的第一次迁移中。

所以条件里面的代码!context.Database.CompatibleWithModel(false)不会运行。

然而,遗憾的是,当它应该有元数据模型时,代码也没有第二次运行。

现在尝试让迁移运行...

悲伤:到目前为止,Radek 的自定义初始化程序没有。

根据 NSGaga 的评论,如果我更改连接,我会退出应用程序。

var master = new myMDIForm();
master.ConnectionType = connectionType;   // being an enum of the different connection names in app.config
while (master.ConnectionType != ConnectionType.None )
{
   Application.Run(master);
}
4

2 回答 2

7

(注意:我不知道您的自定义初始化程序,我只是看到 - 这是connection caching问题和迁移初始化程序的一般解决方案 - 但应该适用于变体)


这对我有用 - 并且基于我在此处描述的错误行为。

static string _connection;
public MyContext()
    : base(_connection ?? "DefaultConection")
{
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyNamespace.Migrations.Configuration>());
}
public MyContext(string connection)
    : base(connection)
{
    _connection = connection;
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyNamespace.Migrations.Configuration>());
}

几点:

1)在您的上下文中定义static连接 - 当您设置“新连接”时,将其更改为保存latest value. 这有助于保持同步 - 无论谁访问 DbContext 都有相同的(它在概念上相似,Factory只是更容易看,

2)问题Migrations是 -MigrateDatabaseToLatestVersion将连接(和内部的整个配置)缓存在内部的readonly字段中 - 即使您在您DbContext.

没有办法解决这个问题,只能制作一个“新的初始化程序”。

3) @Radek 发现的实际上是该问题的解决方案 - 并且符合 (2)。我刚刚删除了它,Initialize(true)因为它是不必要的 - 当“时间合适”时会调用它。


就是这样。

有了这个,我现在可以flip全天候连接 - 并且如我所愿。
(这意味着我可以更改连接runtime- 迁移/创建两个或更多数据库并不断更改连接并同时处理它们)

这是我实际用于在连接之间循环的代码......

for (var flip = true; true; flip = !flip)
{
    using (var db = new MyContext(flip ? "Name=DefaultConnection" : "Name=OtherConnection"))
    {
        // usual db code
    }
}

关键是set initializer each time you set the connection
旧的仍然存在 - 旧的连接(您无法在应用程序运行时删除 Db)

于 2013-04-10T23:20:44.153 回答
0

经过多次洗牌,我得到了这个工作:

Public Class BlogContext
  Inherits DbContext

  Public Sub New()
    Database.Connection.ConnectionString = Utils.SqlCeConnection.ConnectionString
  End Sub



  Private Sub New(Connection As DbConnection)
    MyBase.New(Connection, True)

    Database.SetInitializer(New MigrateDatabaseToLatestVersion(Of BlogContext, Migrations.Configuration))
    Database.Initialize(True)
  End Sub



  Public Shared Function Create() As BlogContext
    Return New BlogContext(Utils.SqlCeConnection)
  End Function



  Public Property Blogs As DbSet(Of Blog)
End Class

这是配置类。注意禁用的 AutomaticMigrations:

Namespace Migrations
  Friend NotInheritable Class Configuration
    Inherits DbMigrationsConfiguration(Of BlogContext)

    Public Sub New()
      Me.AutomaticMigrationsEnabled = False
    End Sub

    Protected Overrides Sub Seed(Context As BlogContext)
    End Sub
  End Class
End Namespace

这是 SqlCeConnection 辅助类,可以在运行时设置数据库位置:

Public Class Utils
  Public Shared ReadOnly Property SqlCeConnection As SqlCeConnection
    Get
      Return New SqlCeConnection(ConnectionString)
    End Get
  End Property



  Public Shared ReadOnly Property SqlCeConnection(DataSource As String) As SqlCeConnection
    Get
      Return New SqlCeConnection(ConnectionString(DataSource))
    End Get
  End Property



  Private Shared ReadOnly Property ConnectionString As String
    Get
      Return ConnectionString(DatabasePath)
    End Get
  End Property



  Private Shared ReadOnly Property ConnectionString(DataSource) As String
    Get
      With New SqlCeConnectionStringBuilder
        .MaxDatabaseSize = 4091
        .MaxBufferSize = 1024
        .CaseSensitive = False
        .FlushInterval = 1
        .DataSource = DataSource
        .FileMode = "Read Write"
        .Encrypt = False
        .Enlist = True

        Return .ConnectionString
      End With
    End Get
  End Property



  Public Shared ReadOnly Property DatabasePath As String
    Get
      Return Path.Combine(DatabaseFolder, DatabaseFile)
    End Get
  End Property



  Public Shared ReadOnly Property DatabaseFile As String
    Get
      Return "MigrationsDemo.sdf"
    End Get
  End Property



  Public Shared ReadOnly Property DatabaseFolder As String
    Get
      DatabaseFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MigrationsDemo")

      If Not Directory.Exists(DatabaseFolder) Then
        Directory.CreateDirectory(DatabaseFolder)
      End If
    End Get
  End Property
End Class

高温高压

于 2014-08-05T09:25:34.257 回答