In my last questions I was creating some methods to automate some queries. It's cool, but now I need to control access to methods by specifying a sequence.
When using the Select () method, I can not access it again. After the Where () method I can not access the LeftJoin () and InnerJoin () methods. This is until the ToList () method is reached definitively;
My class will work by creating sql commands in a chained way like Linq to Lambda.
So:
var pessoas = pessoaDAO.Select()
.LeftJoin(x => x.Telefones, (telefones, pessoa) => telefones.PessoaId == pessoa.Id)
.Where(x => x.Ativo)
.OrderBy(x => x.Nome)
.ToList();
It would be wrong to allow this:
var pessoas = pessoaDAO
.Select(x =>
x.Id,
x => x.Pessoa,
x => x.Ativo,
x => x.Telefones)
.Where(x => x.Ativo)
.Select()
.ToList();
That is, a Select () after a Where () and even a Select () p>
To solve this, I am trying to separate the methods by interface. So:
public interface IQueryBuilder<TModel> : ICustomQueryBuilder<TModel>
where TModel : class
{
ICustomQueryBuilder<TModel> Select();
ICustomQueryBuilder<TModel> Select(params Expression<Func<TModel, object>>[] members);
}
public interface ICustomQueryBuilder<TModel> :
IQueryBuilderJoin<TModel>,
IQueryBuilderFilter<TModel>,
IQueryBuilderOrder<TModel>,
IQueryBuilderExecute<TModel>
where TModel : class
{
}
IQueryBuilder that will be the interface used to implement my class inherits from ICustomQueryBuilder , and the Select () methods return the ICustomQueryBuilder type so that so I can not access the Select () method again.
IQueryBuilder inherits from ICustomQueryBuilder and this from other interfaces because I need to have a type implemented in the class to make the return.
Already, ICustomQueryBuilder inherits from:
public interface IQueryBuilderJoin<TModel> :
IQueryBuilderFilter<TModel>,
IQueryBuilderOrder<TModel>,
IQueryBuilderExecute<TModel>
where TModel : class
{
IQueryBuilderJoin<TModel> LeftJoin<TMemberJoin>(
Expression<Func<TModel, TMemberJoin>> member,
Expression<Func<TMemberJoin, TModel, bool>> filter);
IQueryBuilderJoin<TModel> LeftJoin<TMemberJoin>(
Expression<Func<TModel, IEnumerable<TMemberJoin>>> member,
Expression<Func<TMemberJoin, TModel, bool>> filter);
IQueryBuilderJoin<TModel> InnerJoin<TMemberJoin>(
Expression<Func<TModel, TMemberJoin>> member,
Expression<Func<TMemberJoin, TModel, bool>> filter);
IQueryBuilderJoin<TModel> InnerJoin<TMemberJoin>(
Expression<Func<TModel, IEnumerable<TMemberJoin>>> member,
Expression<Func<TMemberJoin, TModel, bool>> filter);
}
Following:
public interface IQueryBuilderFilter<TModel> : IQueryBuilderOrder<TModel>
where TModel : class
{
IQueryBuilderFilter<TModel> Where(Expression<Func<TModel, bool>> filter);
}
public interface IQueryBuilderOrder<TModel> : IQueryBuilderExecute<TModel>
where TModel : class
{
IQueryBuilderOrder<TModel> OrderBy(params Expression<Func<TModel, object>>[] members);
IQueryBuilderOrder<TModel> OrderByDesc(params Expression<Func<TModel, object>>[] members);
}
public interface IQueryBuilderExecute<TModel>
where TModel : class
{
List<TModel> ToList();
}
Finally, you would have:
public class QueryBuilder<TModel> : IQueryBuilder<TModel>
where TModel : class
{
// ... implementações
}
Is it correct to do this type of implementation?
To better illustrate the need for return, eg:
public class PessoaDAO : GenericDAO<Pessoa>
{
// ... outros métodos
public IQueryBuilderFilter<Pessoa> Where(Expression<Func<TModel, bool>> filter)
{
// ... implementações
return this;
}
// ... outros métodos
}
In other words, this is necessary for concatenating the methods and the type must be a type already implemented, otherwise the automatic cast will not be accepted.