Búsqueda
Visión general
Las búsquedas en Crono se resuelven directamente contra la base de datos con LINQ, a través de dos piezas complementarias:
- Extensiones de consulta (
*ConsultaExtensiones): métodos de extensión reutilizables que encapsulan predicados y filtros sobre unIQueryable<T>. - Buscadores (
*Buscador): servicios por entidad que construyen la consulta aplicando esas extensiones, la paginan y devuelven el resultado.
A diferencia de otros sistemas que dependen de un motor de índices externo (como Lucene) con facetas, Crono no mantiene un índice de búsqueda dedicado: las consultas se traducen a SQL y se ejecutan sobre la base de datos de la organización, aprovechando la caché de segundo nivel y la paginación eficiente descritas en Acceso a datos.
Extensiones de consulta
Encapsular los predicados LINQ en métodos de extensión mejora la reutilización, la legibilidad y el mantenimiento. Crono define numerosas clases *ConsultaExtensiones (por ejemplo UsuarioConsultaExtensiones, IOrganizacionRestringidaConsultaExtensiones), cada una con filtros componibles:
public static partial class UsuarioConsultaExtensiones
{
public static IQueryable<Usuario> AplicarFiltroIdentificador(
this IQueryable<Usuario> consulta,
string correoElectronico = null,
string nombreUsuario = null,
bool coincidenciaExacta = false)
{
Guarda.NoNulo(consulta, nameof(consulta));
if (correoElectronico.TieneValor())
{
consulta = coincidenciaExacta
? consulta.Where(c => c.CorreoElectronico == correoElectronico)
: consulta.Where(c => c.CorreoElectronico.Contains(correoElectronico));
}
if (nombreUsuario.TieneValor())
{
consulta = coincidenciaExacta
? consulta.Where(c => c.NombreUsuario == nombreUsuario)
: consulta.Where(c => c.NombreUsuario.Contains(nombreUsuario));
}
return consulta;
}
}
Buscadores
Un buscador es un servicio (con su interfaz I*Buscador) que centraliza la búsqueda de una entidad: recibe un DTO de filtro, arma la consulta con las extensiones, ordena y pagina, y devuelve un resultado paginado. Existen muchos en el núcleo, por ejemplo: ComentarioBuscador, MonedaBuscador, ImpuestoBuscador, MedioBuscador, BancoBuscador, CajaBuscador, EventoNegocioBuscador, entre otros.
Un buscador típico:
- Parte de un
IQueryable<T>delCronoDbContexto. - Aplica los filtros del DTO mediante las
*ConsultaExtensiones(incluido el filtro por organización conAplicarFiltroOrganizacion). - Aplica el ordenamiento solicitado.
- Pagina con
AListaPaginadaoPaginadorRapido(ver Acceso a datos).
public class BancoBuscador : IBancoBuscador
{
private readonly CronoDbContexto _db;
public BancoBuscador(CronoDbContexto db)
{
_db = db;
}
public async Task<IListaPaginada<Banco>> BuscarAsync(FiltroBancoDto filtro)
{
var consulta = _db.Bancos
.AplicarFiltroOrganizacion()
.AplicarFiltro(filtro) // extensión de consulta específica
.OrderBy(x => x.Nombre);
return await consulta
.AListaPaginada(filtro.IndicePagina, filtro.TamanioPagina)
.CargarAsync();
}
}
Para conjuntos de datos muy grandes, usa PaginadorRapido en lugar de AListaPaginada: evita Skip().Take() recordando el último identificador procesado, lo que ofrece un rendimiento estable en tablas grandes (útil, por ejemplo, en calidad de cartera o listas masivas de préstamos).
Búsqueda global
Además de los buscadores por entidad, la pantalla de inicio ofrece un buscador global que consulta clientes y préstamos a la vez para acceder rápidamente a ellos. Sigue el mismo principio: consulta LINQ paginada sobre la base de datos, optimizada para responder con rapidez.
Crono aún no cuenta con un motor de búsqueda por índices (tipo Lucene) ni con navegación por facetas. Si en el futuro se requiere (por ejemplo, búsqueda de texto completo a gran escala), esta sección se ampliará con ese diseño.