Entity Framework Code-First в C# интерактивное окно (Oracle)

Я пытаюсь использовать интерактивное окно C#, чтобы быстро протестировать часть моего кода. У меня возникают проблемы, когда я пытаюсь проверить код, связанный с DbContext (EF6).

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

Я также должен сказать, что я использую базу данных Oracle с поставщиком ODP.NET.

Вот код, который я пытаюсь запустить в интерактивном окне:

#r "MyProjPath\bin\Debug\CsCore.EntityDomain.dll"
#r "MyProjPath\bin\Debug\EntityFramework.dll"
#r "MyProjPath\bin\Debug\EntityFramework.SqlServer.dll"
#r "MyProjPath\bin\Debug\Oracle.ManagedDataAccess.dll"
#r "MyProjPath\bin\Debug\Oracle.ManagedDataAccess.EntityFramework.dll"
var ctx = new CsCore.EntityDomain.Pivot.PivotContext("Data Source=MyDataSource;User Id=MyUser;Password=MyPassword;");
ctx.ReconciliationRules.FirstOrDefault()

и это исключение, которое я получаю

The underlying provider failed on Open.
  + System.Data.Entity.Core.EntityClient.EntityConnection.Open()
  + System.Data.Entity.Core.Objects.ObjectContext.EnsureConnection(bool)
  + System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction<T>(Func<T>, System.Data.Entity.Infrastructure.IDbExecutionStrategy, bool, bool)
  + System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute<TResult>(Func<TResult>)
  + ObjectQuery<T>.GetResults(Nullable<System.Data.Entity.Core.Objects.MergeOption>)
  + LazyEnumerator<T>.MoveNext()
  + System.Linq.Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>)
  + System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle<TResult>(IEnumerable<TResult>, System.Linq.Expressions.Expression)
  + System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute<TResult>(System.Linq.Expressions.Expression)
  + System.Data.Entity.Internal.Linq.DbQueryProvider.Execute<TResult>(System.Linq.Expressions.Expression)
  + System.Linq.Queryable.FirstOrDefault<TSource>(IQueryable<TSource>)

Мой DbContext выглядит так:

public class PivotContext : DbContext
{
    public virtual DbSet<PivotReconciliationRule> ReconciliationRules { get; set; }

    public PivotContext() : this("name=myConnectionStringName")
    {
    }

    public PivotContext(string nameOrConnectionString) : base(nameOrConnectionString)
    {
        Database.SetInitializer<PivotContext>(null);
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("MYSCHEMA");

        base.OnModelCreating(modelBuilder);
    }
}

Я думаю, что причина в том, что я не могу указать правильный поставщик. Кому-нибудь удалось использовать код EntityFramework (на оракуле), работающий в первую очередь, из интерактивного окна C#?

Спасибо заранее.

Никола

2 ответа

Решение

Мне наконец удалось заставить это работать.

Во-первых, я получал сообщение "Основной провайдер не удалось открыть". потому что EF не смог получить правильный провайдер и фабрику соединений. На самом деле он пытался использовать фабрику соединений SqlServer, а не Oracle. В подходе, основанном на базе данных, вы могли бы создать DbContext из EntityConnection, который указывает поставщика. К сожалению, похоже, что в этом случае вы также должны предоставить модель, которая не применима к коду в первую очередь.

В конце я решил настройку провайдера / фабрики, следуя информации в этом посте. Соответствующий код csx:

System.Data.Entity.DbConfiguration.Loaded += (_, a) =>
{
    var services = Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices.Instance;
    a.ReplaceService<System.Data.Entity.Core.Common.DbProviderServices>((s, k) => services);
    var factory = new Oracle.ManagedDataAccess.EntityFramework.OracleConnectionFactory();
    a.ReplaceService<System.Data.Entity.Infrastructure.IDbConnectionFactory>((s, k) => factory);
};

После этого я все еще получил следующую ошибку: Невозможно определить имя поставщика для фабрики поставщиков типа "Oracle.ManagedDataAccess.Client.OracleClientFactory". Убедитесь, что поставщик ADO.NET установлен или зарегистрирован в конфигурации приложения.

Это было связано с тем, что OracleClientFactory не был связан с провайдером платформы сущностей (из раздела "entityFramework"). Я не смог сделать это напрямую из кода. В итоге я добавил раздел "entityFramework" в мой machine.config:

Объявление настроек configSections:

<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name="oracle.manageddataaccess.client" type="OracleInternal.Common.ODPMSectionHandler, Oracle.ManagedDataAccess, Version=4.122.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />

Содержимое configSection:

<entityFramework>
  <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
    <parameters>
      <parameter value="mssqllocaldb" />
    </parameters>
  </defaultConnectionFactory>
  <providers>
    <provider invariantName="Oracle.ManagedDataAccess.Client" type="Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices, Oracle.ManagedDataAccess.EntityFramework, Version=6.122.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
    <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  </providers>
</entityFramework>

<system.data>
  <DbProviderFactories>
    <remove invariant="Oracle.ManagedDataAccess.Client" />
    <add name="ODP.NET, Managed Driver" invariant="Oracle.ManagedDataAccess.Client" description="Oracle Data Provider for .NET, Managed Driver" type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess, Version=4.122.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
    ... other staff that was already there
  </DbProviderFactories>
</system.data>

С этими конфигами я наконец-то смог использовать свой код EF6, написанный первым кодом Oracle, в интерактивном окне C#.

Прежде всего, вы можете использовать свой App.Config и ваши строки подключения из конфигурации вашего приложения:

var AppConfig = System.Configuration.ConfigurationManager.OpenExeConfiguration(@"bin\Debug\MyApp.exe");
Console.WriteLine($"Loaded {AppConfig.ConnectionStrings.ConnectionStrings.Count} connection strings");

В общем, вам нужно реализовать метод OnConfiguring в вашем DbContext (здесь для postgresql в ядре 2.0):

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseNpgsql("Host=localhost; Database=mydb; User ID=myuser; Password=mypasswd; Port=0000; ");
}

OnConfiguring вызывается в первый раз, когда вы используете контекст.

Мне нужен ваш DbContext, чтобы помочь вам больше.

Другие вопросы по тегам