Есть ли способ напрямую запросить базу данных в памяти, используемую Entity Framework Core? - PullRequest
1 голос
/ 16 января 2020

Я использую провайдера базы данных в памяти, чтобы провести несколько тестов приложения. Net Core 2.2. Мне нужно сделать одну из таблиц в приложении недоступной - либо переименовав ее, либо отбросив. Есть ли способ выполнить такой запрос непосредственно к БД в памяти? Я пытался получить соединение, используя:

context.Database.GetDbConnection();

, но это выдает ошибку

Методы Relational-Speci c могут использоваться только тогда, когда контекст использует поставщик реляционных баз данных.

Я знаю, что могу уничтожить всю базу данных с помощью:

context.Database.EnsureDeleted();

, но мне нужно сохранить ее и уничтожить или переименовать только одну таблицу.

1 Ответ

2 голосов
/ 17 января 2020

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

Вместо этого вы можете использовать режим SQLite в памяти ( do c), затем создайте перехватчик, который перехватывает введенные команды EF, и либо подавляет создание таблицы, либо подавляет другие запросы, направленные на эту таблицу.

public class MyInterceptor : DbCommandInterceptor {
    public override InterceptionResult<int> NonQueryExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<int> result) {
        if (ContainsBannedTable(command)) {
            //suppress the operation
            result = InterceptionResult<int>.SuppressWithResult(0);
        }
        return base.NonQueryExecuting(command, eventData, result);
    }

    private bool ContainsBannedTable(DbCommand command) {
        //or custom logic
        return command.CommandText.Contains("ToDeleteEntity");
    }
}

следующий вызовет исключение (Microsoft.EntityFrameworkCore.DbUpdateException... SqliteException: SQLite Error 1: 'no such table: ToDeleteEntity') при попытке доступа к нежелательной таблице.

var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
var options = new DbContextOptionsBuilder<MyContext>()
                  .UseSqlite(connection)
                  .AddInterceptors(new MyInterceptor())
                  .Options
                  ;

var context = new MyContext(options);
context.Database.EnsureCreated();

context.AllowedEntity.Add(new AllowedEntity { Id = 1 });
context.SaveChanges();
Console.WriteLine(context.AllowedEntity.FirstOrDefault()?.Id); //1 - ok

context.ToDeleteEntity.Add(new ToDeleteEntity { Id = 1 });
//will throw an exception
context.SaveChanges();
Console.WriteLine(context.ToDeleteEntity.FirstOrDefault()?.Id);

//close the connection and clean up
//...
public class MyContext : DbContext {
    public MyContext(DbContextOptions options) : base(options) {
    }

    public DbSet<AllowedEntity> AllowedEntity { get; set; }
    public DbSet<ToDeleteEntity> ToDeleteEntity { get; set; }
}

public class ToDeleteEntity {
    public int Id { get; set; }
}

public class AllowedEntity {
    public int Id { get; set; }
}
...