【问题标题】:Entity Framework 6 Programmatically Connect to PostgresEntity Framework 6 以编程方式连接到 Postgres
【发布时间】:2023-03-23 10:40:02
【问题描述】:

我正在使用 Entity Framework 6 以编程方式建立与 PostgresSQL 的连接。我有这个类:

public class ClearspanDatabaseContext : DbContext

使用这个构造函数:

public ClearspanDatabaseContext()
    : base(buildConnectionString())
{
}

这是以编程方式生成连接字符串的静态方法:

private static string buildConnectionString()
{
    RegisterDbProvider("Npgsql", ".Net Framework Data Provider for Postgresql", "Npgsql Data Provider", "Npgsql.NpgsqlFactory, Npgsql");
    EntityConnectionStringBuilder entityConnectionStringBuilder = new EntityConnectionStringBuilder();
    entityConnectionStringBuilder.Provider = "Npgsql";
    entityConnectionStringBuilder.ProviderConnectionString = "host=192.168.168.140;Port=5432;username=ClearspanDevLogin;password=*******;database=ClearspanWebServerDev";
    return entityConnectionStringBuilder.ToString();
}

这是将 Npgsql 注册为数据库提供程序的方法,取自 source

public static bool RegisterDbProvider(string invariant, string description, string name, string type)
{
    try
    {
        DataSet ds = ConfigurationManager.GetSection("system.data") as DataSet;
        foreach (DataRow row in ds.Tables[0].Rows)
        {
            if (row["InvariantName"].ToString() == invariant)
            {
                return true;
            }
        }
        ds.Tables[0].Rows.Add(name, description, invariant, type);
        return true;
    }
    catch
    {
    }
    return false;
}

这会生成一个这样的字符串:

"provider=Npgsql;provider connection string=\"host=192.168.168.140;Port=5432;username=ClearspanDevLogin;password=********;database=ClearspanWebServerDev\""

但我得到一个ArgumentException

不支持关键字:'provider'。

我认为我接近编程连接,但缺少一些小东西。我可以做些什么来解决此异常并以编程方式正确设置此连接?没有 app.config 答案,我在一个忽略 app.config 的类库中工作(请参阅此question 已接受答案的 cmets)。该程序必须保持这种状态,因为它被用作插件 - 它不会(也不应该)自行运行。提前致谢。

【问题讨论】:

  • 你试过new DbContext(new System.Data.Entity.Core.EntityClient.EntityConnection(buildConnectionString()), true)吗?该 DbContext 构造函数可能不支持指定提供者。

标签: entity-framework database-connection entity-framework-6 connection-string npgsql


【解决方案1】:
  1. 你看过Code-Based Configuration吗?在与 DbContext 相同的程序集中创建一个带有公共无参数构造函数的 DbConfiguration

    class MyConfiguration : System.Data.Entity.DbConfiguration
    {
        public MyConfiguration()
        {
            SetProviderServices("Npgsql", Npgsql.NpgsqlServices.Instance);
            SetProviderFactory("Npgsql", Npgsql.NpgsqlFactory.Instance);
        }
    }
    

    现在我认为DbContext 应该默认使用该提供程序工厂,您可以仅使用连接字符串构造DbContext。但如果它在不同的程序集中,那么您还有更多工作要做,但可以在上面的链接中找到。

  2. 上述解决方案的一个潜在问题是配置文件中的任何配置都将优先,因此使用here中描述的选项可能会更安全:

    var conn = DbProviderFactories.GetFactory("MY_CONN_PROVIDER").CreateConnection();
    conn.ConnectionString = "MY_CONN_STR";
    
    new DbContext(conn, true);
    

    您的提供者是"Npgsql",在上面的RegisterDbProvider 中注册。

    另见https://msdn.microsoft.com/en-us/library/dd0w4a2z(v=vs.110).aspx

【讨论】:

  • 谢谢,我正在尝试处理其中的一些内容。在实施第二个选项时,我在var conn = DbProviderFactories.GetFactory("Npgsql").CreateConnection();“无法找到或加载已注册的 .Net Framework 数据提供程序”这一行上收到错误消息。虽然看起来RegisterDbProvider 方法确实有效。关于可能出现什么问题的任何想法?
  • @NickG:根据您之前提到的,这是在另一个应用程序正在使用的库/插件中。也许您可以检查主应用程序本身是否知道在哪里可以找到 npgsql DLL?
  • 感谢您的帮助。我检查了这个过程,插件确实可以访问 Npgsql.dll。我会赞成你的问题,因为它在概念上对我有帮助,尽管我已经验证接受的答案可以回答我的问题。
【解决方案2】:

好的,这是我验证的工作示例。 使用虚拟代码优先 EF 6 模型 + 自定义 DbConfiguration 类:

public class Enrollment {
    public int EnrollmentID { get; set; }
    public int CourseID { get; set; }
    public int StudentID { get; set; }
}

[DbConfigurationType(typeof (NpgsqlConfiguration))]
public class SchoolContext : DbContext {
    public SchoolContext(string cs) : base(cs) {
    }

    public DbSet<Enrollment> Enrollments { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {

    }
}

class NpgsqlConfiguration : System.Data.Entity.DbConfiguration
{
    public NpgsqlConfiguration()
    {
        SetProviderServices("Npgsql", Npgsql.NpgsqlServices.Instance);
        SetProviderFactory("Npgsql", Npgsql.NpgsqlFactory.Instance);
        SetDefaultConnectionFactory(new Npgsql.NpgsqlConnectionFactory());
    }
}

然后,而不是你的 buildConnectionString(),只需在构造函数中传递 postgre 连接字符串:

using (var ctx = new SchoolContext("host=192.168.168.40;port=5432;...")) {                
            Console.WriteLine(ctx.Enrollments.ToArray());
        } 

仅此而已。配置文件在此期间完全为空,并且可以正常工作。

【讨论】:

  • 我使用 Code First 是否合适?我不确定我将使用的 .csdl 和 .ssdl 文件在哪里。我认为它们是 Database First 的产物。
  • 并非如此。使用代码优先,元数据将在第一次连接(动态)时生成,因此所有这些 .csdl 仍然存在(尽管对您来说是透明的)。但这与您的问题没有直接关系。在您的情况下 - 尝试直接使用提供者连接字符串(而不是 EF 连接字符串),所以原始 postgre 连接字符串。您的错误是因为 EF 尝试解析您传递给它的连接字符串。它看到没有“元数据”参数,所以它不是 EF 字符串。所以它是原始的 postgre 连接字符串。然后它看到“provider”选项并且不知道它是什么。
  • 好的,如果不需要元数据,我不确定你建议我如何修改我的代码。
  • @NickG 用建议更新了我的答案。
  • 谢谢,但我收到“在 mscorlib.dll 中发生类型为 'System.ArgumentException' 的异常但未在用户代码中处理附加信息:参数 'xmlReader' 无效”的错误. 必须至少提供一个 .ssdl 工件。”我的元数据字符串最终是“res://DatabaseConnection, Version=1.2.5731.17066, Culture=neutral, PublicKeyToken=null/” DatabaseConnection 库中实际上没有 EF,所以我尝试使用Assembly.GetAssembly(typeof(Distance)),它确实使用 EF,但元数据字符串看起来很相似,不包含任何 .ssdl 内容。
猜你喜欢
  • 2014-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-24
相关资源
最近更新 更多