使用Entity Framework中的动态连接字符串进行迁移代码优先(来自文本文件的连接字符串)

时间:2016-10-30 14:50:56

标签: entity-framework ef-code-first connection-string code-first ef-migrations

我首先使用EF6代码,首先,我将连接字符串放在名为“Settings.txt”的文本文件中

'Settings.txt'文件中的数据是

DataProvider: sqlserver
DataConnectionString: Data Source=.\SQLEXPRESS;Initial Catalog=MyDb;Integrated Security=True;Persist Security Info=False;Enlist=False;

这里我用于dbContext类:

public class DbDataContext : BaseDbContext
{
    static DbDataContext()
    {
        Database.SetInitializer(new ContextInitializer());
    }

    public DbDataContext():base() { }

    public DbDataContext(string nameOrConnectionString)
        : base(nameOrConnectionString) { }

    ...    
}

[DbConfigurationType(typeof(MyDbConfiguration))]
public abstract partial class BaseDbContext : DbContext, IDbContext
{
    public BaseDbContext() : this(GetConnectionString())
    { }

    public BaseDbContext(string nameOrConnectionString) : base(nameOrConnectionString)
    { }

    public static string GetConnectionString()
    {
        if (DataSettings.DataSettings.Current.IsValid())
        {
            return DataSettings.DataSettings.Current.DataConnectionString;
        }

        throw Error.Application("A connection string could not be resolved for the parameterless constructor of the derived DbContext. Either the database is not installed, or the file 'Settings.txt' does not exist or contains invalid content.");
    }
}

public class MyDbConfiguration : DbConfiguration
{
    public MyDbConfiguration()
    {
        IEfDataProvider provider = null;

        try
        {
            provider = (new EfDataProviderFactory(DataSettings.DataSettings.Current).LoadDataProvider()) as IEfDataProvider;
        }
        catch {
        }

        if (provider != null)
        {
            base.SetDefaultConnectionFactory(provider.GetConnectionFactory());
        }
    }
}

public partial class EfDataProviderFactory : DataProviderFactory
{
    public EfDataProviderFactory()
        : this(DataSettings.DataSettings.Current){ }

    public EfDataProviderFactory(DataSettings.DataSettings settings)
        : base(settings) { }

    public override IDataProvider LoadDataProvider()
    {
        var providerName = Settings.DataProvider;

        if (providerName.IsEmpty())
        {
            throw new Exception("Data Settings doesn't contain a providerName");
        }

        switch (providerName.ToLowerInvariant())
        {
            case "sqlserver":
                return new SqlServerDataProvider();

            case "sqlserverce":
                return new SqlServerCeDataProvider();

            default:
                throw new Exception(string.Format("Unsupported dataprovider name: {0}", providerName));
        }
    }
}

public class SqlServerDataProvider : IEfDataProvider
{
    public virtual IDbConnectionFactory GetConnectionFactory()
    {
        return new SqlConnectionFactory();
    }

    public bool StoredProceduresSupported
    {
        get { return false; }
    }

    public DbParameter GetParameter()
    {
        return new SqlParameter();
    }

    public string ProviderInvariantName
    {
        get { return "System.Data.SqlClient"; }
    }
}

我在'BaseDbContext'类中使用一个名为'GetConnectionString()'的静态函数

此函数仅用于从文本文件返回连接字符串。此行为在运行时非常有效,但在添加迁移时无效。

这就是问题:如何通过这种方式添加迁移,知道当我将连接字符串直接放在像这样的函数中时

    public static string GetConnectionString()
    {
         return (@"Data Source=.\\SQLEXPRESS;Initial Catalog=MyDb;Integrated Security=True;Persist Security Info=False;Enlist=False;");
    }

Add-Migration命令正在运行

如何在不强制代码中的连接字符串的情况下解决此问题?

2 个答案:

答案 0 :(得分:1)

我解决了这个, 在设计模式甚至是获取文件路径(文本文件)时会出现问题 单元测试

string filePath = Path.Combine(MapPath("~/App_Data/"), "Settings.txt");
public static string MapPath(string path)
    {
            path = path.Replace("~/", "").TrimStart('/').Replace('/', '\\');

            var testPath = Path.Combine(baseDirectory, path);

            var dir = FindSolutionRoot(baseDirectory);

            if (dir != null)
                {
                    baseDirectory = Path.Combine(dir.FullName, "MyProjectName.WebAPI");
                    testPath = Path.Combine(baseDirectory, path);


            return testPath;
        }
    }
private static DirectoryInfo FindSolutionRoot(string currentDir)
    {
        var dir = Directory.GetParent(currentDir);
        while (true)
        {
            if (dir == null || IsSolutionRoot(dir))
                break;

            dir = dir.Parent;
        }

        return dir;
    }

    private static bool IsSolutionRoot(DirectoryInfo dir)
    {
        return File.Exists(Path.Combine(dir.FullName, "MySolutionName.sln"));
    }

通过这个,我们可以在运行时模式

中获取文件路径

答案 1 :(得分:0)

我猜您在程序包管理器控制台中使用Add-Migration命令。

如果您手动运行Add-Migration,只需将连接字符串添加为-ConnectionString参数:

Add-Migration -ConnectionString "Data Source=.\\SQLEXPRESS;Initial Catalog=MyDb;Integrated Security=True;Persist Security Info=False;Enlist=False;"

除非您在-ConnectionProviderName中定义了提供商,否则您可能还需要添加参数app.config

我建议您停止使用此Settings.txt文件,并将连接字符串移至app.config文件的connectionStrings部分。这是处理连接字符串的推荐方法,比使用Settings.txt文件之类的自定义文件要容易得多。

<connectionStrings>
  <add name="MyLocalDatabase" connectionString="Data Source=.\\SQLEXPRESS;Initial Catalog=MyDb;Integrated Security=True;Persist Security Info=False;Enlist=False;" />
</connectionStrings>

如果这样做,您可以使用在app.config中定义的名称在程序包管理器控制台中使用参数-ConnectionStringName

Add-Migration -ConnectionStringName "MyLocalDatabase"

此外,使用app.config文件中的连接字符串,您可以向上下文添加构造函数,该构造函数接收连接字符串名称作为参数,并且可以在使用程序包管理器控制台时使用:

public DbDataContext():base("MyLocalDatabase") { }

这将允许您在Package Manager控制台中运行命令,而无需指定任何连接字符串参数。只需确保在控制台中选择的启动项目的app.config文件中包含正确的连接字符串。

您可以删除GetConnectionString代码。您只是在使用app.settings connectionString部分时重新实现开箱即用的代码。那就是如何使用DbContext基础构造函数参数NameOrConnectionString。您可以提供完整的连接字符串或app.settings文件中定义的连接字符串的名称。