Skip to content

akhakpouri/daytona

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build & Pack

Daytona

This is a simple little library built to solve a complex problem - wrap your queries inside of a single unit-of-work to use accordingly.

How to get started?

First, configure the DbContext using a desired database framework. Make sure you're pasing through the DbContextOptions when creating your model.

public class YourDbContext : DbContext
{
    public YourDbContext(DbContextOptions<YourDbContext> options) : base(options) { }
    public YourDbContext() { }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ///... modelbuilder configs
        modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
        base.OnModelCreating(modelBuilder);
    }
}

Larger appliacations will require multiple type configurations, and as the scope of the application grows, the developer will have to remember to register all new type configurations. A new extension methid, ApplyConfigurationsFromAssembly, was introduced in .net-standard-2.2 which scans a given assembly for all types and implement IEntityTypeConifugration, and registers each one automatically.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    ///.. optionbuildr configs
    base.OnConfiguring(optionsBuilder);
}

When creating an entity, make sure you either inherit from BaseEntity or BaseCompleteEntity depending on which properties you like to inherit.

Create a project level IYourProjectUnitOfWork interface inheriting IUnitOfWork<YourDbContext> passing in the DbContext created in the first step.

public interface IYourUnitOfWork : IUnitOfWork<YourDbContext>
{
    IRepository<MyEntity> MyRepository { get; }
    IRepository<FooEntity> FooRepository { get; }
    IRepository<BarEntity> BarRepository { get; }
}

public class YourUnitOfWork : UnitOfWork<YourDbContext>, IYourUnitOfWork
{
    public IRepository<MyEntity> MyRepository => new Repository<MyEntity>(Context);
    public IRepository<FooEntity> FooRepository => new Repository<FooEntity>(Context);
    public IRepository<BarEntity> BarRepository => new Repository<BarEntity>(Context);
    
    public YourUnitOfWork(YourDbContext context) : base(context) { }
}

When creating the entity type configuration, you must choose between BaseNpsqlEnttityConfiguration or BaseSqlEntityConfiguration depending on your database's flavor. You can override the Configure method to include your additional property/column configurations.

How do I use it in the manager layer?

Daytona's EfCore is more than just a data-layer extension. It can also provide you with an robust library to use the UnitOfWork as easily as possible.

First, Create an interface for your manager. Feel free to make it generic, and inherit it from IManager<IYourUnitOfWork, TDto>; but, you have to make sure TDto is inheriting from the BaseDto. Something like this:

public interface IYourManager<TDto> : IManager<IYourUnitOfWork, TDto> where TDto : BaseDto {}

After this, you can choose to create more specific manager level interfaces by inheriting your wrapping interface, or continue to use this interface for all CRUD operations.

Bulk Edit & Delete

This library uses efficient update & delete to manipulate multiple records using a single query. You can do this by invoking the BulkUpdate or BulkDelete methods defined in the Repository.

Update

    await _unitOfWork.EntityRepository.BulkUpdate(
        a => true, 
        a => a.SetProperty(e => e.Property = value));

The method above produces the following sql query statement.

UPADTE [Entity]
SET [Property] = _value_
WHERE
    1 = 1;

Delete

    await _unitOfWork.EntityRepository.BulkDelete(a => a.property = value);

The method above produces the following sql query statement.

DELETE FROM [Entity]
WHERE
    [property] = _value_;

Let's talk Implementation!

When implementing your manager, you must inherit from the base abstract Manager class as well as the interface defined above.

IMapper and IUnitOfWork are already registredd into the abstract manager's contructor; therefore, you don't have to worry about creating private readonly variables for those.

Eager Loading

Ef-Core suppors eager loading of related entities, using Include() iextension method and projection query. In addition, you can also use ThenInclude() method to load multiple levels of relation entities.

Look at the following example:

var x  = (await _unitOfWork.FooRepository.GetAll(a => true, a => a.Include(a => a.Bar))).FirstOrDefaultAsync();

In the above example, .Include(a => a.Bar) passes the lambda expression a => a.Bar to specify a reference property to loadedwith Foo entity data from the database in a single SQL query. The above query executes the following SQL query in the database

SELECT TOP(1) [a].*
FROM [Foo] AS [a]
LEFT JOIN [Bar] AS [a.Bar] ON [a].[BarId] = [s.Bar].[Id]
WHERE 1 = 1 

Where can I get it?

First, install NuGet. Then, add akhakpouri as a source to your nuget configuration. Lastly, install Daytona from the package manager console:

PM> Install-Package Daytona --source "akhakpouri"

Or from the .NET CLI as:

dotnet add package Daytona --source "akhakpouri"

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages