簡體   English   中英

為實體框架核心 DbContext 創建一個接口以便可以注入/測試它?

[英]Creating an Interface for an Entity Framework Core DbContext so that it can be injected/tested?

我有一個相當基本的 Entity Framework Core DbContext 用於我的應用程序。 我正在注入此上下文,但我想進一步解耦上下文,以便我可以進行測試和/或將其替換為不同的上下文/數據庫。

為 DbContext 創建適當接口的最佳實踐方法是什么?

我的數據庫上下文:

public partial class MyContext : DbContext
{
    private string _connectionString;
    public MyContext(DbContextOptions<MyContext> options) : base(options){}
    public MyContext(string connectionString) => _connectionString = connectionString;

    public virtual DbSet<Address> Addresses { get; set; }
    public virtual DbSet<Person> Persons{ get; set; }
    public virtual DbSet<Detail> Details{ get; set; }
    public virtual DbSet<Order> Orders { get; set; }
    ...(about 35 additional tables)
}

在我的界面中,我是否需要為每個 DbSet 公共成員創建一個成員? 有沒有辦法讓界面更簡單?

然后我需要為每個成員創建一個接口嗎? 然后是這些成員的子成員的接口,等等......(我需要到 go 的兔子洞多遠?)

您不需要為數據庫中的每個所需表指定一個 DBSet。 唯一需要 DBSet 的表是您計划直接訪問的表。 在 EF Core 中,您的實體應該在對象之間建立關系,以便您可以執行更復雜的查詢。 例如,您可能永遠不需要拼命訪問訂單的詳細信息,您應該能夠檢索訂單及其詳細信息以檢索/更改您需要的內容(通過 context.Orders.Include(x => x.Details) 之類的命令.FindAsync(id))。

如果您要測試 DbContext,我建議您使用 Moq.EntityFrameworkCore 庫https://github.com/MichalJankowskii/Moq.EntityFrameworkCore 它是最接近復制 DbContext 工作方式的能力。 也可以啟動一個內存數據庫進行測試,您可以在此處閱讀: https://docs.microsoft.com/en-us/ef/core/providers/in-memory/?tabs=dotnet-核心-cli

我不建議在測試時不先評估支持 DBContext 的可用選項就嘗試從 DbContex 抽象回接口。

EF 的設計理念是您將更換提供程序進行測試,而不是用其他東西替換 DbContext。 如果您確實想通過 DbContext 對存儲庫抽象進行編程,這樣的事情還不錯:

public interface IRepository : IDisposable
{
    void Add<TEntity>(TEntity entity) where TEntity : class;
    void Update<TEntity>(TEntity entity) where TEntity : class;
    void Remove<TEntity>(TEntity entity) where TEntity : class;
    IQueryable<TEntity> Query<TEntity>() where TEntity : class;
    TEntity GetById<TEntity, TId>(TId id) where TEntity : class;
    int SaveChanges();
}

在您的 DbContext 中實現如下:

void IRepository.Add<TEntity>(TEntity entity)
{
    Add(entity);
}

void IRepository.Update<TEntity>(TEntity entity)
{
    Update(entity);
}

void IRepository.Remove<TEntity>(TEntity entity)
{
    Remove(entity);
}

IQueryable<TEntity> IRepository.Query<TEntity>()
{
    return Set<TEntity>();
}

TEntity IRepository.GetById<TEntity, TId>(TId id)
{
    var entity = Set<TEntity>().Find(id);
    if (entity == null)
        throw new InvalidOperationException($"No Entity {typeof(TEntity).Name} found for id {id}");

    return entity;
}

int IRepository.SaveChanges()
{
    return this.SaveChanges();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM