Как использовать DbContext в отдельной библиотеке классов. net ядро? - PullRequest
1 голос
/ 15 января 2020

Я пытаюсь получить доступ к своему dbcontext из моего проекта. net core 3.1 MVC в библиотеке классов. В настоящее время я внедряю свою базу данных в коллекцию сервисов в startup.cs

public class AppDbContext : DbContext
{
    public DbSet<User> Users {get; set;}
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    { }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        // Handles duplicate entry for email in user table
        builder.Entity<User>()
            .HasIndex(u => u.Email)
            .IsUnique();
    }
}

Однако я не уверен, как получить доступ к этому AppDbContext в моей библиотеке классов. Я попытался получить к нему доступ, как к контроллеру, но, очевидно, он не знает о контейнере DI.

Дополнительная информация: Эта библиотека используется для распространенных запросов. Он всегда должен быть отделен от основного веб-приложения, и пользователю никогда не придется кодировать в этой библиотеке классов. Поэтому мне нужно иметь доступ к dbcontext, который в основном веб-проекте, из библиотеки классов.

Ответы [ 2 ]

1 голос
/ 15 января 2020

Как вы сказали, вы разрабатываете библиотеку классов для использования любых DbConext, передаваемых клиентом библиотеки, тогда вы должны сделать следующее:

Сначала рассмотрите, что ваша библиотека классов имеет следующие интерфейсы и классы, где ваш DbCoenxt будет использоваться:

public interface IUnitOfWork 
{
    IRepository<T> Repository<T>() where T : class;
    Task SaveChangesAsync();
}

internal class UnitOfWork : IUnitOfWork
{
    private readonly DbContext _dbContext;
    private Hashtable _repositories;
    public UnitOfWork(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IRepository<T> Repository<T>() where T : class
    {
        if (_repositories == null)
            _repositories = new Hashtable();

        var type = typeof(T).Name;

        if (!_repositories.ContainsKey(type))
        {
            var repositoryType = typeof(Repository<>);

            var repositoryInstance =
                Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), _dbContext);

            _repositories.Add(type, repositoryInstance);
        }

        return (IRepository<T>)_repositories[type];
    }

    public async Task SaveChangesAsync()
    {
        await _dbContext.SaveChangesAsync();
    }
}

public interface IRepository<TEntity> where TEntity : class
{
     Task InsertEntityAsync(TEntity entity);
}

internal class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
    private readonly DbContext _dbContext;
    public Repository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task InsertEntityAsync(TEntity entity)
    {
        await _dbContext.Set<TEntity>().AddAsync(entity);
    }
 }

Теперь напишите метод расширения коллекции сервисов в вашей библиотеке классов следующим образом:

public static class ServiceCollectionExtensions
{

    public static void RegisterYourLibrary(this IServiceCollection services, DbContext dbContext)
    {
        if (dbContext == null)
        {
            throw new ArgumentNullException(nameof(dbContext));
        }

        services.AddScoped<IUnitOfWork, UnitOfWork>(uow => new UnitOfWork(dbContext));
    }
}

Теперь в Startup.ConfigureServices вашего клиентского приложения следующим образом:

public void ConfigureServices(IServiceCollection services)
{
    string connectionString = Configuration.GetConnectionString("ConnectionStringName");
    services.AddDbContext<AppDbContext>(option => option.UseSqlServer(connectionString));

    ServiceProvider serviceProvider = services.BuildServiceProvider();
    AppDbContext appDbContext = serviceProvider.GetService<AppDbContext>();

    services.RegisterYourLibrary(appDbContext); // <-- Here passing the DbConext instance to the class library

    .......
}

Использование:

public class EmployeeController : Controller
{
    private readonly IUnitOfWork _unitOfWork;

    public EmployeeController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public async Task<IActionResult> Insert()
    {
        Employee employee = new Employee();
        await _unitOfWork.Repository<Employee>().InsertEntityAsync(employee);
        await _unitOfWork.SaveChangesAsync();
        return View();
    }
}
1 голос
/ 15 января 2020

если вы создали свой dbcontext в другом проекте / lib, вам сначала нужно перенести его и обновить. EF использует IDesignTimeDbContextFactory, чтобы уведомить об обрамлении сущности о lib.

 public class ContextFactoryNeededForMigrations : IDesignTimeDbContextFactory<AppDbContext >
    {
        private const string ConnectionString =
            "Server=(localdb)\\mssqllocaldb;Database=EfCoreInActionDb;Trusted_Connection=True;MultipleActiveResultSets=true";

        public EfCoreContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<EfCoreContext>();
            optionsBuilder.UseSqlServer(ConnectionString,
                b => b.MigrationsAssembly("DataLayer"));

            return new EfCoreContext(optionsBuilder.Options);
        }

Затем вы можете добавить его в свой DI-контейнер startup.cs следующим образом.

 services.AddDbContextPool<AppDbContext >( 
                options => options.UseSqlServer(connection,
                b => b.MigrationsAssembly("DataLayer"))); 

Вот хороший учебник по этому вопросу. введите описание ссылки здесь

...