lundi 24 juillet 2017

DAL using Dapper

I'm creating my first project using ASP.NET Core and Dapper. Before this project I used Entity Framework. DAL in my past projects was like this:

// Project.Data

public class BaseRepository : IDisposable
{
    public string ConnectionString { get; set; }

    protected BaseRepository()
    {
    }

    protected BaseRepository(string connectionString)
    {
        ConnectionString = connectionString;
    }

    protected string GetConnectionStringValue(string connectionStringName)
    {
        ...
    }
}

// Project.Data.EF

public abstract class EntityBaseRepository : BaseRepository
{
    private DbContext _context;
    protected EntityBaseRepository(): base("connectionString")
    {
    }

    protected DbContext Context => _context ?? (_context = CreateEntityContext(GetConnectionStringValue(ConnectionString)));
    protected abstract DbContext CreateEntityContext(string connectionString);

    protected virtual void SaveEntity<T>(T entity) where T : Entity
    {
        ...
    }

    protected virtual void DeleteEntity<T>(T entity) where T : Entity
    {
        ...
    }
}

public abstract class EntityBaseRepository<TEntity, TSearchOptions, TLoadOptions> : EntityBaseRepository
    where TEntity : Entity
    where TSearchOptions : SearchOptions
    where TLoadOptions : LoadOptions
{
    protected IEnumerable<TEntity> GetEntities(TSearchOptions searchOptions, TLoadOptions loadOptions)
    {
        ...
    }

    protected async Task<IEnumerable<TEntity>> GetEntitiesAsync(TSearchOptions searchOptions, TLoadOptions loadOptions)
    {
        ...
    }

    protected int GetCount(TSearchOptions searchOptions)
    {
        ...
    }

    protected TEntity GetEntity(long id, TLoadOptions loadOptions)
    {
        ...
    }

    protected virtual IQueryable<TEntity> ApplySearchOptions(
        DbContext context, IQueryable<TEntity> entities, TSearchOptions searchOptions)
    {
        ...
    }

    protected virtual IQueryable<TEntity> ApplyLoadOptions(
        DbContext context, IQueryable<TEntity> entities, TLoadOptions loadOptions)
    {
        ...
    }
}

I thought I can use this approach with dapper. I have created mapper for entities and query builder. After that I have created Repository:

    public abstract class EntityBaseRepository<TEntity, TKey, TSearchOptions, TLoadOptions> : EntityBaseRepository
    where TEntity : Entity<TKey>
    where TSearchOptions : SearchOptions
    where TLoadOptions : LoadOptions
{
    ...

    protected virtual Query ApplySearchOptions(QueryBuilder query, TSearchOptions searchOptions)
    {
        if (searchOptions.IDs.Any())
            query.WhereIn(FluentMapper.KeyColumnName<TEntity>().ToArray(), searchOptions.IDs);

        return query;
    }

    protected virtual Query ApplyLoadOptions(QueryBuilder query, TLoadOptions loadOptions)
    {
        if (loadOptions.SortFields.Any())
        {
            foreach (var sortField in loadOptions.SortFields)
            {
                switch (sortField.Value)
                {
                    case SortOrder.Ascending:
                        break;
                    case SortOrder.Descending:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
        }

        if (loadOptions.SkipRecords.HasValue)
            query.Skip(loadOptions.SkipRecords.Value);

        if (loadOptions.MaxRecords.HasValue)
            query.Take(loadOptions.MaxRecords.Value);

        return query;
    }
}

QueryBuilder is fluent query constructor (like sqlkata). The main problem when using this approach with Dapper is applying search and load options. I don't know how to do it properly. If in derived from EntityBaseRepository class I use alias (for example QueryBuilder.From("x as A")), I will receive exception.

How would you create DAL with dapper?

Aucun commentaire:

Enregistrer un commentaire