• 让EF Power Tools CTP1识别自定义数据库连接串


    近在学习Entity Framework:Code-First,安装了Entity Framework Power Tools CTP1后,在实际使用过程中遇到了一个问题,即我在app.config中自定义的数据库连接串不能被EF Power Tools识别,使我无法查看由代码生成的实体数据模型。


    统环境:Windows 7 64位旗舰版,Visual Studio 2010旗舰版,Entity Framework 4.2,Entity Framework Power Tools CTP1

    这是一个做练习用的Console项目,只有简单的2个文件:POCO.cs里是我Code-First的类,Program.cs里是主程序Main()。刚开始使用的是本地的SQL Server 2008 Express作的数据库。由于EF会自动使用和连接本地的SQL Server Express,因此之前的练习很顺利。每次右键点击POCO.cs,均能正常查看生成的数据模型图,并在数据库正确地生成所有的表。

    view model

    随后,我为了尝试远程连接,因此在项目中添加了如下内容的app.config

    app.config

    于是问题来了。当我需要查看实体数据模型时,总是在长时间的等待后,得到如下的错误提示。

    Error

    尽管如此,我运行这个简单的控制台程序,仍能正确地更新和生成数据库中的表。只是无法经由EF Power Tools显示实体数据模型而已。

    我尝试了在DbContext的派生类的构造子中传入连接串,尝试了在Main()里设置默认的连接工厂(参见上图背景中第4行代码),也尝试了改为安装Entity Framework 4.1,均未能解决问题。无奈之下,只得四处求助。


    终,我在StackOverflow上的问题得到了Devart的热情解答,给了我一个他们团队的Blog链接 Using Entity Framework Power Tools CTP1 with Oracle, MySQL, PostgreSQL, and SQLite,使得问题得到了较为圆满的解决。在该文中,他们介绍了4种解决方案:

    1. 把连接串写入.NET Framework 4.0安装目录下的machine.config里;

    2. 把连接串写入Visual Studio 2010的配置文件devenv.exe.config里;

    3. 实现一个IDbConnectionFactory的自定义连接工厂,设置项目的缺少连接工厂(就象我此前尝试的一样,但我没放对地方);

    4. 使用特定数据库的连接串,并将其传递给DbContext派生类构造子(我之前也尝试了,但我传递的是连接串本身,而不是连接对象)。

    过思考,我最终选择了方案3:自定义连接工厂,并在DbContext派生类的静态构造子中设置项目的数据库缺省连接工厂。

    · 自定义的连接工厂

    public class PocoConnectionFactory : IDbConnectionFactory
    {
        public DbConnection CreateConnection(string nameOrConnectionString)
        {
            // connectionString="Data Source=CASPER-PC\SQL_Abbey;Database=BreakAway;Integrated Security=True"
            var builder = new SqlConnectionStringBuilder
            {
                DataSource = @"CASPER-PC\SQL_Abbey",
                InitialCatalog = @"BreakAway",
                IntegratedSecurity = true,
                MultipleActiveResultSets = true
            };
    
            return new SqlConnection(builder.ToString());
        }
    }

    · 在DbContext派生类的静态构造子中设置数据库缺省的连接工厂

    public class BreakAwayContext : DbContext
    {
        // ... ...
    
        static BreakAwayContext()
        {
            Database.DefaultConnectionFactory = new PocoConnectionFactory();
        }
    }

    Devart给出的那篇文章里,选择了更为灵活的工厂实现方式,而不是我为了做练习而使用的硬编码方式。 期待EF Power Tools的下个完善版本。

    public class DevartConnectionFactory : IDbConnectionFactory
    {
        public DevartConnectionFactory(string providerInvariantName, string configFileName)
        {
            this.ProviderInvariantName = providerInvariantName;
            this.ConfigFileName = configFileName;
        }
    
        public DbConnection CreateConnection(string nameOrConnectionString)
        {
            if (String.IsNullOrWhiteSpace(nameOrConnectionString))
                throw new ArgumentNullException("nameOrConnectionString");
    
            DbProviderFactory providerFactory = DbProviderFactories.GetFactory(ProviderInvariantName);
            if (providerFactory == null)
                throw new InvalidOperationException(String.Format("The '{0}' provider is not registered on the local machine.",
                                                                    ProviderInvariantName));
    
            DbConnection connection = providerFactory.CreateConnection();
    
            if (nameOrConnectionString.Contains("="))
                connection.ConnectionString = nameOrConnectionString;
            else
            {
                string dbContextClassName = nameOrConnectionString;
                if (dbContextClassName.Contains('.'))
                {
                    int classNameFrom = nameOrConnectionString.LastIndexOf('.') + 1;
                    int classNameLength = nameOrConnectionString.Length - classNameFrom;
                    dbContextClassName = nameOrConnectionString.Substring(classNameFrom, classNameLength);
                }
    
                ExeConfigurationFileMap map = new ExeConfigurationFileMap();
                map.ExeConfigFilename = this.ConfigFileName;
                Configuration assemblyConfig = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
    
                ConnectionStringSettings connectionSettings = assemblyConfig.ConnectionStrings.ConnectionStrings[dbContextClassName];
    
                if (connectionSettings == null)
                    throw new InvalidOperationException(String.Format("Can't find the '{0}' connection string in the config file.",
                                                                        dbContextClassName));
    
                if (connectionSettings.ProviderName != ProviderInvariantName)
                    throw new InvalidOperationException(
                        String.Format(
                            "The '{0}' connection string was expected to be defined for the '{1}' provider, but it is defined for the '{2}' provider.",
                            dbContextClassName, ProviderInvariantName, connectionSettings.ProviderName));
    
                connection.ConnectionString = connectionSettings.ConnectionString;
            }
    
            return connection;
        }
    
        public string ProviderInvariantName { get; set; }
        public string ConfigFileName { get; set; }
    }

    转载请注明出处及作者,谢谢!
  • 相关阅读:
    Java编译器API简介
    liblinear和libsvm区别
    spark和hadoop比较
    maxout激活函数
    FTRL算法
    NLP里面好的学习资料
    阿里妈妈MLR模型(论文)
    FM的推导原理--推荐系统
    GBDT+LR simple例子
    深度学习最全优化方法---来源于知乎
  • 原文地址:https://www.cnblogs.com/Abbey/p/2343347.html
Copyright © 2020-2023  润新知