HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Fluent Repository/QueryBuilder

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
querybuilderfluentrepository

Problem

I've been toying around making my repositories a bit more fluent for a while. I was ending up with crazy long method names when I had to query on multiple conditions. So I've been working on a way to query fluently.

Usage

Insert/Update/Delete

Looks and behaves exactly like a normal repository.

var personRepository = new PersonRepository(dbContext);

personRepository.Insert(new Person {...});
personRepository.Update(person);
personRepository.Remove(person);


Querying

Allows you to call any query methods, narrowing down the query more and more as you go and can execute the query synchronously or asynchronously.

var person = await personRepository.Query()
    .ByFirstName("neil")
    .ByLastName("smith")
    .Include(m => m.Addresses)
    .OrderBy(m => m.LastName)
    .Take(5)
    .ToEntitiesAsync();

var person = personRepository.Query()
    .ById(99)
    .ToEntity();

var person = await personRepository.Query()
    .WhereFirstNameContains("jr")
    .ToEntitiesAsync();


So the code behind this:

Entity Base Class

public abstract class BaseEntity
{
    public int Id { get; set; }
    public DateTime DateCreated { get; set; }
}


Repository Contracts

```
public interface IPersistableRepository where TEntity : BaseEntity
{
void Insert(TEntity entity);
void Update(TEntity entity);
void Remove(TEntity entity);
}

public interface IQueryableRepository
where TEntity : BaseEntity
where TQueryBuilder : class, IQueryBuilder
{
TQueryBuilder Query();
}

public interface IQueryBuilder
where TEntity : BaseEntity
where TQueryBuilder : class
{
TQueryBuilder ById(int id);
...

TQueryBuilder Include(Expression> prop);
TQueryBuilder OrderBy(Expression> prop);
TQueryBuilder OrderByDescending(Expression> prop);
TQueryBuilder Take(int count);
TQueryBuilder After(int id);
TQueryBuilder Before(int id);

TEntity ToEntity();
Task ToEntityAsync();
IEnumerable ToEntities();
Task> To

Solution

I quite like the concept. The only thing that stands out for me initially is that I would probably leave the wrapping methods the same as their wrapped name.

i.e.

TEntity FirstOrDefault()
Task FirstOrDefaultAsync()
IEnumerable All()
Task> AsEnumerable();


rather than

TEntity ToEntity();
Task ToEntityAsync();
IEnumerable ToEntities();
Task> ToEntitiesAsync();


I guess my main reasoning is that FirstOrDefault makes it clear what we are retrieving where as ToEntity() leaves it open to thought between Single() and First().

Neat idea thought. Be interested to see what others think.

Code Snippets

TEntity FirstOrDefault()
Task<TEntity> FirstOrDefaultAsync()
IEnumerable<TEntity> All()
Task<IEnumerable<TEntity>> AsEnumerable();
TEntity ToEntity();
Task<TEntity> ToEntityAsync();
IEnumerable<TEntity> ToEntities();
Task<IEnumerable<TEntity>> ToEntitiesAsync();

Context

StackExchange Code Review Q#54120, answer score: 2

Revisions (0)

No revisions yet.