EF6 +迁移+ SqlServer / SqlCe4

时间:2014-11-14 00:26:36

标签: entity-framework sql-server-ce ef-migrations

我有一个针对双数据库SqlServer / SqlCe4的EF5 +迁移解决方案。 我有一个代码切换来设置适当的连接。 这一切都很好。

但是现在我想要EF6的一些功能,所以我升级了。 最初它与SqlServer一起使用但我遇到了SqlCe的主要问题。 错误:"指定的表已存在。 [TableName]"

现在它不适用于任何一个: "指定的索引已存在。 [IX_TableNameId]"

在工厂中创建连接:

public static class ContextFactory
{
    static ContextFactory()
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<SongServiceDataContext, SongServiceConfiguration>());
    }

    public static SongServiceDataContext GetClientContext()
    {
        // Get path
        var path = ConfigurationManager.AppSettings["LocalDbPath"];

        // Create SqlCe connection
        var sb = new SqlCeConnectionStringBuilder { DataSource = path };
        var con = new SqlCeConnection(sb.ToString());

        return new SongServiceDataContext(con);
    }

    public static SongServiceDataContext GetServerContext()
    {
        // Get connectionstring
        var connectionString = ConfigurationManager.AppSettings["ServerConnectionString"];
        if (!connectionString.IsSpecified())
            throw new Exception("AppSetting 'ServerConnectionString' must be specified in config file");

        // Create SqlServer connection
        var sb = new SqlConnectionStringBuilder(connectionString);
        var con = new SqlConnection(sb.ToString());

        return new SongServiceDataContext(con);
    }
}

我决定删除数据库并使用初始创建重新启动迁移。 Add-Migration InitalModel -ProjectName:&#34; MyApp.Business&#34; 这会导致以下错误:

System.ArgumentException: The ADO.NET provider with invariant name 'v11.0' is either not registered in the machine or application config file, or could not be loaded. See the inner exception for details. ---> System.ArgumentException: Unable to find the requested .Net Framework Data Provider.  It may not be installed.
   at System.Data.Common.DbProviderFactories.GetFactory(String providerInvariantName)
   at System.Data.Entity.Infrastructure.DependencyResolution.DefaultProviderFactoryResolver.GetService(Type type, Object key, Func`3 handleFailedLookup)
   --- End of inner exception stack trace ---
   at System.Data.Entity.Infrastructure.DependencyResolution.DefaultProviderFactoryResolver.<GetService>b__0(ArgumentException e, String n)
   at System.Data.Entity.Infrastructure.DependencyResolution.DefaultProviderFactoryResolver.GetService(Type type, Object key, Func`3 handleFailedLookup)
   at System.Data.Entity.Infrastructure.DependencyResolution.DefaultProviderFactoryResolver.GetService(Type type, Object key)
   at System.Data.Entity.Infrastructure.DependencyResolution.CachingDependencyResolver.<>c__DisplayClass1.<GetService>b__0(Tuple`2 k)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at System.Data.Entity.Infrastructure.DependencyResolution.CachingDependencyResolver.GetService(Type type, Object key)
   at System.Data.Entity.Infrastructure.DependencyResolution.ResolverChain.<>c__DisplayClass3.<GetService>b__0(IDbDependencyResolver r)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
   at System.Data.Entity.Infrastructure.DependencyResolution.ResolverChain.GetService(Type type, Object key)
   at System.Data.Entity.Infrastructure.DependencyResolution.RootDependencyResolver.GetService(Type type, Object key)
   at System.Data.Entity.Infrastructure.DependencyResolution.ResolverChain.<>c__DisplayClass3.<GetService>b__0(IDbDependencyResolver r)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
   at System.Data.Entity.Infrastructure.DependencyResolution.ResolverChain.GetService(Type type, Object key)
   at System.Data.Entity.Infrastructure.DependencyResolution.CompositeResolver`2.GetService(Type type, Object key)
   at System.Data.Entity.Infrastructure.DependencyResolution.DbDependencyResolverExtensions.GetService[T](IDbDependencyResolver resolver, Object key)
   at System.Data.Entity.Infrastructure.SqlCeConnectionFactory.CreateConnection(String nameOrConnectionString)
   at System.Data.Entity.Internal.LazyInternalConnection.Initialize()
   at System.Data.Entity.Internal.LazyInternalConnection.get_Connection()
   at System.Data.Entity.Internal.LazyInternalContext.get_Connection()
   at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config, DbConnectionInfo connectionInfo, Func`1 resolver)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState, Boolean calledByCreateDatabase)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
   at System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Run()
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Scaffold(String migrationName, String language, String rootNamespace, Boolean ignoreChanges)
   at System.Data.Entity.Migrations.AddMigrationCommand.Execute(String name, Boolean force, Boolean ignoreChanges)
   at System.Data.Entity.Migrations.AddMigrationCommand.<>c__DisplayClass2.<.ctor>b__0()
   at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
The ADO.NET provider with invariant name 'v11.0' is either not registered in the machine or application config file, or could not be loaded. See the inner exception for details.

它看起来像配置错误所以我检查了指定项目的App.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <provider invariantName="System.Data.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" />
    </providers>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
        <parameter value="System.Data.SqlClient" />
        <parameter value="System.Data.SqlServerCe.4.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
</configuration>

我试图改变一切,所以我现在有点沮丧。

感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

错误实体框架消息非常具有误导性。主要问题实际上更多是在上下文创建方面。在我的上下文类中,我有两个构造函数,一个用连接初始化,一个参数少一些:

public MyDataContext(DbConnection conn): base(conn, true)
{
}

public MyDataContext()
{
}

我终于意识到,即使我没有调用参数less构造函数,它实际上也是通过迁移多次调用的。这引起了很多困惑......

据我了解,现在以正确方式指导迁移的正确方法是让上下文工厂实现IDbContextFactory。我试图调用特定的方法来创建每个上下文,但迁移仍然在后台调用IDbContextFactory Create方法。我没有找到一种可靠的方法来决定要调用的上下文。

在我的情况下,实际上有一个全局切换,因为每个调用程序集总是使用相同的上下文。所以我决定在工厂类上设置一个静态属性。它在应用程序启动时设置,然后将创建指向正确的方向。

public class ContextFactory : IDbContextFactory<MyDataContext>
{
    public static DbSource DefaultDbSource = DbSource.Client;

    static ContextFactory()
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<SongServiceDataContext, SongServiceConfiguration>());
    }

    /// <summary>
    /// This is called by the migration.
    /// </summary>
    public MyDataContext Create()
    {
        return GetContext();
    }

    /// <summary>
    /// This is added for my convenience.
    /// </summary>
    public static MyDataContext GetContext()
    {
        return DefaultDbSource == DbSource.Client ? GetClientContext() : GetServerContext();
    }


    #region Private Methods

    private static MyDataContext GetClientContext()
    {
        // Get path
        var dirDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        var dirData = Path.Combine(dirDocuments, "MyApplication", "Data");
        if (!Directory.Exists(dirData))
            Directory.CreateDirectory(dirData);
        var path = Path.Combine(dirData, "MyApplicationData.sdf");

        // Create SqlCe connection
        var sb = new SqlCeConnectionStringBuilder {DataSource = path};
        var con = new SqlCeConnection(sb.ToString());

        return new MyDataContext(con);
    }

    private static MyDataContext GetServerContext()
    {
        // Get connectionstring
        var connectionString = ConfigurationManager.AppSettings["ServerConnectionString"];
        if (!connectionString.IsSpecified())
            throw new Exception("AppSetting 'ServerConnectionString' must be specified in config file");

        // Create SqlServer connection
        var sb = new SqlConnectionStringBuilder(connectionString);
        var con = new SqlConnection(sb.ToString());

        return new SongServiceDataContext(con);
    }

    #endregion
}

提示:即使在我解决了这个工厂设置后,我也遇到了一些问题。迁移进行得很顺利,但之后的每个连接都会导致各种奇怪的问题。我挣扎了几个小时,接近放弃了。简单清理和重建我的解决方案做了最后的伎俩!看来补余文件一定会造成一些混乱。

答案 1 :(得分:0)

部分:

<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
  <parameters>
    <parameter value="v11.0" />
    <parameter value="System.Data.SqlClient" />
    <parameter value="System.Data.SqlServerCe.4.0" />
  </parameters>
</defaultConnectionFactory>

完全坏了,配置文件中缺少SQLCE的几个版本。

创建一个新的空控制台应用程序,并安装EntityyFramework.SqlServerCompact包以获取正确的配置设置