EF6和多个配置(SQL Server和SQL Server Compact)

23

更新:问题已解决,请查看本问题的结尾。

问题:

我们正在尝试在同一个AppDomain中同时使用SQL Server和SQL Server CE,并使用Entity Framework 6和代码配置。然而这个简单的场景似乎不被“设计支持”。EF团队表示:

注意:我们不支持在同一个AppDomain中使用多个配置类。如果您使用此属性设置两个上下文的不同配置类,将引发异常。

更多信息请参见:Code-based Configuration (Codeplex)

问题:

我们如何从这里继续前进?任何帮助都将非常感激!除了AppDomain之外,是否有一种更灵活的方式将配置连接到上下文?(我们的上下文类位于不同的程序集中。我们已经尝试过DbConfigurationType属性,但问题仍出在EF本身)

配置文件:

正常SQL服务器的配置

public class EfConfiguration : DbConfiguration
{
    public EfConfiguration()
    {
        SetProviderServices(
            SqlProviderServices.ProviderInvariantName, 
            SqlProviderServices.Instance);

        SetDefaultConnectionFactory(new SqlConnectionFactory());
    }
}

SQL Server Compact Edition 的配置

public class EfCeConfiguration : DbConfiguration
{
    public EfCeConfiguration()
    {
        SetProviderServices(
            SqlCeProviderServices.ProviderInvariantName,
            SqlCeProviderServices.Instance);

        SetDefaultConnectionFactory(
            new SqlCeConnectionFactory(SqlCeProviderServices.ProviderInvariantName));
    }
}

更新:

我们遇到的错误是:

System.TypeInitializationException:'MyProject.Repositories.Base.DataContext' 的类型初始化程序引发了异常。----> System.InvalidOperationException:设置了 'EfCeConfiguration' 的实例,但此类型没有在与 'DataContext' 上下文相同的程序集中发现。将 DbConfiguration 类型放置在与 DbContext 类型相同的程序集中,或者在 DbContext 类型上使用 DbConfigurationTypeAttribute 指定 DbConfiguration 类型,或在配置文件中设置 DbConfiguration 类型。有关更多信息,请参见http://go.microsoft.com/fwlink/?LinkId=260883

更新2,解决方法: 如上所述,我们只能拥有一个配置。这是一个问题,因为Sql和SqlCe使用不同的提供程序。如果我们使用“SetDefaultConnectionFactory”来适配一种类型的数据库,则另一个将失败。

相反,像下面标记为答案的帖子所述,将连接提供给上下文。一旦您始终使用连接而不是连接字符串初始化上下文,就可以开始工作了。您可以从配置中删除 SetDefaultConnectionFactory 调用。我们只使用以下代码配置 SqlCe 上下文,并且没有为 Sql 上下文进行任何配置。

  public class CommonEfConfiguration : DbConfiguration
    {
        public CommonEfConfiguration()
        {
            // EF does not know if the ce provider by default,
            // therefore it is required to be informed about it.
            // The connection factories are not necessary since the connection
            // is always created in the UnitOfWork classes
            SetProviderServices(SqlCeProviderServices.ProviderInvariantName, SqlCeProviderServices.Instance);
        }
    }

我有点困惑——我在两个不同的C#项目(程序集)中有两个数据库,每个数据库都有自己的配置,并且从来没有遇到任何问题。 - Kirk Woll
Kirk:你在使用EF6吗?并且它们在同一个应用程序域中执行吗?我们使用nunit,在两个系统之间执行集成测试,但将其作为一个系统运行。在EF5中可以正常工作,其中不需要在配置中指定提供程序。 - Henrik Carlsson
是的,没错。你遇到了什么实际错误? - Kirk Woll
@Henrik,区别在于我的配置包含在与我的数据上下文相同的程序集中。您不能这样做的原因是什么? - Kirk Woll
@Kirk,问题解决了!问题在于我们使用连接字符串创建DbContext,而当您想要连接到Sql和SqlCe时,这与单例连接工厂不匹配。相反,我们现在使用特定连接创建DbContext。现在可以删除工厂的配置。 - Henrik Carlsson
显示剩余5条评论
3个回答

13

编辑:基于错误详细信息: 您是否已经尝试告诉 EF 配置类的位置?

[DbConfigurationType("MyNamespace.MyDbConfiguration, MyAssemblyFullyQualifiedName")]
public class MyContextContext : DbContext
{
}
如果那不能生效,那么请尝试替代方案。
使用带有构造函数 DbConnection 的上下文。
public class MYDbContext : DbContext {
     // MIgration parameterless constructor is managed in  MyMigrationsContextFactory 

    public MyDbContext(string connectionName) : base(connectionName) { } // no this

    public MYDbContext(DbConnection dbConnection, bool contextOwnsConnection)  // THIS ONE
        : base(dbConnection, contextOwnsConnection) {  }

然后你需要为每个提供程序创建一个“DBConnection”连接。

对于SQL服务器

      public DbConnection GetSqlConn4DbName(string dataSource, string dbName) {
        var sqlConnStringBuilder = new SqlConnectionStringBuilder();
        sqlConnStringBuilder.DataSource = String.IsNullOrEmpty(dataSource) ? DefaultDataSource : dataSource;
        sqlConnStringBuilder.IntegratedSecurity = true;
        sqlConnStringBuilder.MultipleActiveResultSets = true;

        var sqlConnFact = new SqlConnectionFactory(sqlConnStringBuilder.ConnectionString);
        var sqlConn = sqlConnFact.CreateConnection(dbName);
        return sqlConn;
    }

就 SqlCe 工厂而言,它也可以生成一个 DBConnection。SqlCe 连接工厂创建连接


是的,我确实尝试为两个配置文件指定它。这是我收到的消息。 - Henrik Carlsson
谢谢你!我们已经采用了你的CE连接概念,但对于常规连接,我们使用了连接字符串。当我们提供一个连接给上下文时,配置就不再必要了!(除了提供程序定义) - Henrik Carlsson
1
你可以提到MyAssembly必须是一个完全限定的名称。 - quillbreaker
@phil soady 你知道 Oracle 提供的服务吗? - Amir
我从未使用过Oracle的EF提供程序。请访问他们的网站以了解更多信息。http://www.oracle.com/technetwork/topics/dotnet/downloads/odpnet-ef-nuget-121022-2585735.txt - phil soady
未来的观众可以参考以下有用的链接。该链接解释了如何配置各个部分。https://msdn.microsoft.com/zh-cn/data/jj680699 - Pangamma

2

我的工作内容:

public partial class MyDataBaseContext : DbContext
{
    public MyDataBaseContext (string ConnectionString)
        : base(ConnectionString)
    {
    }
}

1
使用类似于 var ConnectionString = @"Data Source="C:\temp\mydatabase.sdf" 的语法是可以正常工作的。 - Mare Infinitus
从我的MVC HomeController类中,我做了这个:public static readonly string conStr = ConfigurationManager.ConnectionStrings["SudentConext"].ToString();MyDataBaseContext db = new MyDataBaseContext(conStr); - Dan Randolph

-1

我在微软论坛帖子中找到了解决方案。

基本上,我有两个项目,每个项目都有自己的上下文。Entity Framework只加载了(第一个)DbConfiguration类中的一个,并尝试将此相同的配置用于两个项目。这就是错误消息说

"设置了“EfCeConfiguration”的实例,但在与“DataContext”上下文不在同一程序集中发现此类型"的原因。

所以,正如那个微软论坛帖子中有人建议的那样,在两个项目中继承自DbContext的类中删除所有[DbConfigurationType(typeof(DbConfigurationClass))]的标注,错误就不会再发生了。


3
但是之后它是否运行了呢?我的意思是,您使用的DbConfiguration子类对其在运行时正确运行非常重要。它配置了许多特定于数据库引擎的内容(例如,MySQL与MSSQL的完全不同设置),如依赖项解析器(例如MySqlDependencyResolver)、提供程序工厂(例如MySqlClientFactory)、提供程序服务(例如MySqlProviderServices)、连接工厂(例如MySqlConnectionFactory)、迁移生成器、提供程序工厂解析器、清单标记解析器和历史上下文。您不能不指定所有这些并使其正常工作。 - Triynko
我不知道,兄弟。我不记得我回答时正在进行的项目的详细信息,但我肯定它当时解决了手头的问题。现在,为了检查你所指出的问题,我认为你将能够更好地测试它,因为我不再有这个问题发生的环境了。 - Ulysses Alves

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接