mardi 16 juin 2020

Unit Of Work Factory with multiples DbContext

I'm creating a new project solution for one application that already has a database created, and in this database, we have 3 versions for each table (Archived, Deleted and Active).

This is an example of the code that we have today

public class MyEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public enum eStatus
{
    Active,
    Archived,
    Deleted,
}

public class MyContext : DbContext
{
    public eStatus Status { get; }

    public MyContext(DbContextOptions<MyContext> options, eStatus status = eStatus.Active)
        : base((DbContextOptions)options)
    {
        this.Status = status;
    }

    public virtual DbSet<MyEntity> MyEntities { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity((Action<EntityTypeBuilder<MyEntity>>)(entity =>
        {
            switch (this.Status)
            {
                case eStatus.Archived:
                    entity.ToTable("MyEntity_Archived");
                    break;
                case eStatus.Deleted:
                    entity.ToTable("MyEntity_Deleted");
                    break;
                case eStatus.Active:
                    entity.ToTable("MyEntity");
                    break;
            }
            entity.HasKey(e => e.Id as object);
        }));
    }
}

public interface IMyRepository
{
    List<MyEntity> Get();
}

public class MyRepository : IMyRepository
{
    private readonly MyContext _context;

    public MyRepository(MyContext context)
    {
        _context = context;
    }

    public List<MyEntity> Get()
    {
        return _context.MyEntities.ToList();
    }
}

public interface IUnitOfWork
{
    IMyRepository MyRepository { get; }
}

public class UnitOfWork : IUnitOfWork
{
    private readonly MyContext _myContext;

    public UnitOfWork(MyContext myContext)
    {
        _myContext = myContext;
    }

    private IMyRepository _myRepository;

    public IMyRepository MyRepository => _myRepository ??= new MyRepository(_myContext);
}

public interface IUnitOfWorkFactory
{
    IUnitOfWork Build(eStatus status = eStatus.Active);
}

public class UnitOfWorkFactory : IUnitOfWorkFactory
{
    private readonly IServiceProvider _serviceProvider;

    public UnitOfWorkFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
    public IUnitOfWork Build(eStatus status = eStatus.Active)
    {
        var context = _serviceProvider.GetServices<MyContext>().First(x => x.Status == status);

        return new UnitOfWork(context);
    }
}

public static class DependencyInjectionExtensions
{
    public static void RegisterServices(this IServiceCollection services, IConfiguration configuration)
    {
        var myContextOptions = new DbContextOptionsBuilder<MyContext>();
        myContextOptions.UseSqlServer(configuration.GetConnectionString("MyConnectionString"));

        services.AddTransient(x => new MyContext(myContextOptions.Options, eStatus.Active));
        services.AddTransient(x => new MyContext(myContextOptions.Options, eStatus.Archived));
        services.AddTransient(x => new MyContext(myContextOptions.Options, eStatus.Deleted));
        services.AddScoped<IUnitOfWorkFactory, UnitOfWorkFactory>();
    }
}

The problem is that with this code, we cannot use the UnitOfWork and the repositories from DI. We have to create a new instance inside the method Build and then create a instance of the repository inside the UnitOfWork class.

Is there any better way or best practices to do that, since we already have the database created with this configurations?

Aucun commentaire:

Enregistrer un commentaire