Как настроить ProviderManifestToken для EF Code First

У меня есть проект asp.net MVC3, использующий код EF в первую очередь. Для моего модульного тестирования я использовал SQL Server CE 4.0 и SQL Server 2008 Express. Оба отлично работали с EF, генерируя мою базу данных, как и ожидалось.

Однако, когда я запускаю свое приложение вне модульного теста и указываю на строки подключения, я получаю ошибку

ProviderIncompatibleException: поставщик не возвратил строку ProviderManifestToken

Я прочитал документацию MS по этому вопросу, и кажется, что это SqlVersion маркер, который генерирует модель EF. Проблема в том, что я использую код первый подход, поэтому у меня нет .edmx файл, и я не знаю, куда указывать информацию о моих метаданных, потому что БД еще не была сгенерирована.

Я знаю, что мои строки подключения, поскольку имя базы данных, имя пользователя и пароль верны, потому что изменение их на неправильные значения приводит к ожидаемой ошибке. Не уверен, с чего начать.

Благодарю.

Вот моя строка подключения:

<connectionStrings>
  <add
    name="SqlConnection"
    providerName="System.Data.SqlClient"
    connectionString="Data Source=WORKSTATION\SQLEXPRESS;Initial Catalog=CodeFirst;Integrated Security=False;
    Persist Security Info=False;User ID=CodeFirst_user;Password=password1;Connect Timeout=120;MultipleActiveResultSets=True;"/>
</connectionStrings>

9 ответов

Если вы используете EF 6 (только что выпущенный), у вас есть альтернатива.

Разрешение зависимостей

Вы можете использовать новую функцию разрешения зависимостей, чтобы зарегистрировать реализацию IManifestTokenResolver (описано в этой предварительной документации как IManifestTokenService).

Эта статья дает немного больше информации о том, как использовать DbConfiguration, Самый простой способ использовать его так:

DbConfigurationType(typeof(EntityFrameworkDbConfiguration))]
public class MyContextContext : DbContext
{
}

В этом примере исключается любое обращение к базе данных при создании метаданных для соединений с SQL Server, и автоматически указывается совместимость с SQL Server 2005.

using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Infrastructure.DependencyResolution;
using System.Data.SqlClient;

/// <summary>
/// A configuration class for SQL Server that specifies SQL 2005 compatability.
/// </summary>
internal sealed class EntityFrameworkDbConfiguration : DbConfiguration
{
    /// <summary>
    /// The provider manifest token to use for SQL Server.
    /// </summary>
    private const string SqlServerManifestToken = @"2005";

    /// <summary>
    /// Initializes a new instance of the <see cref="EntityFrameworkDbConfiguration"/> class.
    /// </summary>
    public EntityFrameworkDbConfiguration()
    {
        this.AddDependencyResolver(new SingletonDependencyResolver<IManifestTokenResolver>(new ManifestTokenService()));
    }

    /// <inheritdoc />
    private sealed class ManifestTokenService : IManifestTokenResolver
    {
        /// <summary>
        /// The default token resolver.
        /// </summary>
        private static readonly IManifestTokenResolver DefaultManifestTokenResolver = new DefaultManifestTokenResolver();

        /// <inheritdoc />
        public string ResolveManifestToken(DbConnection connection)
        {
            if (connection is SqlConnection)
            {
                return SqlServerManifestToken;
            }

            return DefaultManifestTokenResolver.ResolveManifestToken(connection);
        }
    }
}

После долгих поисков и поисков я нашел способ сделать это. Оказывается DbModelBuilder класс занимает DbProviderInfo в его Build метод, поэтому я использую это вместо того, чтобы полагаться на EF для вызова OnModelCreated:

// 'Entities' is my DbContext subclass, the "container" in EF terms.
public static Entities GetNewContext()
{
    // Get a connection, for example:
    var connection = new SqlConnection(GetConnectionString());

    // Create a DbModelBuilder
    var modelBuilder = new DbModelBuilder();
    // Configure the model builder.
    // I changed my DbContext subclass - added a public version of OnModelCreated and called it ConfigureModelBuilder
    Entities.ConfigureModelBuilder(modelBuilder);

    // Here's where the magic happens.
    // Build the model and pass the ProviderManifestToken (I use 2005 to avoid a bug in precision of sql datetime columns when using concurrency control)
    var model = modelBuilder.Build(new System.Data.Entity.Infrastructure.DbProviderInfo("System.Data.SqlClient", "2005"));
    // Compile the model
    var compiledModel = model.Compile();

    // Create the container (DbContext subclass). Ideally all the previous stuff should be cached.
    return new Entities(connection, compiledModel, true);
}

Очевидно, что это требует некоторой реорганизации (например, кешировать скомпилированную модель, чтобы вам не нужно было перестраивать ее каждый раз при создании контекста).

Для меня это полностью решило проблему. Наслаждайтесь!

У меня была именно эта проблема, но я проследил, чтобы служба SQL Server не работала. Я только что перезагрузил свой компьютер, и обычно он запускается сам по себе, но не по какой-то причине.

В моем случае имя строки подключения должно совпадать с именем класса контекста.

Строка подключения:

<connectionStrings>
  <add name="NunuContext" connectionString="Data Source=|DataDirectory|Nunu.sdf" providerName="System.Data.SqlServerCe.4.0" />
</connectionStrings>

Класс контекста:

using System.Data.Entity;
namespace Nunu.Models
{
    public class NunuContext : DbContext
    {
        System.Data.Entity.DropCreateDatabaseIfModelChanges<Nunu.Models.NunuContext>());

        public DbSet<Nunu.Models.NunuFirst> NunuFirsts { get; set; }

        public DbSet<Nunu.Models.NunuLast> NunuLasts { get; set; }
    }
}

У меня была эта проблема при работе с учебником MVC3 на ASP.NET.

Мое решение оказалось в использовании (localhost) вместо именованного источника данных. Это отлично работает на моем компьютере, для локальной работы разработчика, но не помогло бы, если бы база данных была на отдельном сервере.

Переход на Data Source=localhost у меня работал также с использованием MS SQL 2008 R2 Express

Изменение источника данных на localhost в connectionString решил мою проблему.

Я обнаружил, когда я предоставил явное "User Id=abcUser; Password=somePwd;" в моей строке подключения я могу решить ту же ошибку. Ранее я использовал "Trusted_Connection=true;", который позволил мне отладить мой веб-проект, но начал давать мне ошибку - {"Поставщик не возвратил строку ProviderManifestToken."}, Как только я добавил проект Windows Azure и попытался отладить проект Azure после добавления моего веб-проекта в качестве веб-роли под ним.

Надеюсь, это поможет кому-то, находящемуся в подобной ситуации.

Спасибо, Вивек Баль

Я вижу некоторые комментарии о Oracle выше, поэтому вот код для EntityFrameworkDbConfiguration, скорректированный для Oracle:

internal sealed class EntityFrameworkDbConfiguration : DbConfiguration
{
    /// <summary>
    /// Initializes a new instance of the <see cref="EntityFrameworkDbConfiguration"/> class.
    /// </summary>
    public EntityFrameworkDbConfiguration()
    {
        this.AddDependencyResolver(Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices.Instance);
    }
}

Это оказалось полезным для меня:

<connectionString="Data Source=WORKSTATION\SQLEXPRESS;Initial Catalog=CodeFirst;User ID=CodeFirst_user;Password=********"/> 
</connectionStrings> 
Другие вопросы по тегам