01

Qué es y qué problema resuelve

Cuando necesitas el mismo filtro en varios lugares, repetirlo facilita que las versiones se vuelvan distintas. Specification Pattern permite darle un nombre y conservar el criterio en un solo objeto.

En este ejemplo, ReservasActivasDelGrupo selecciona reservas que pertenecen a un grupo y siguen activas. El criterio describe qué incluir; un evaluador decide cómo aplicarlo.

Expression<Func<T, bool>> representa la condición como una estructura que un proveedor puede inspeccionar. Al llamar Compile se obtiene un delegado: una función que evalúa objetos ya cargados en memoria.

02

Ejemplo paso a paso

Specification Pattern: criterios y evaluadores · caso de reservasC#

Punto de partida El tipo Reserva y la colección reservas pertenecen al laboratorio descargable. La interfaz conserva el criterio como expresión y la clase le da un significado. En EF Core, el modelo y el proveedor deben admitir su traducción.

Antes de ejecutar

Usa los tipos del núcleo del laboratorio .NET descargable. El fragmento ilustra la regla local; no configura HTTP ni persistencia.

using System.Linq.Expressions;
public interface IEspecificacion<T>
{
    Expression<Func<T, bool>> Criterio { get; }
}
public sealed class ReservasActivasDelGrupo(string grupoId)
    : IEspecificacion<Reserva>
{
    public Expression<Func<Reserva, bool>> Criterio =>
        r => r.GrupoId == grupoId && !r.Cancelada;
}

public static class ConsultaEjemplo
{
    public static List<Reserva> Filtrar(IEnumerable<Reserva> reservas)
    {
        var spec = new ReservasActivasDelGrupo("grupo-lima");
        return reservas.Where(spec.Criterio.Compile()).ToList();
    }
}
// En un proveedor compatible: origen.Where(spec.Criterio), sin Compile.

Cómo funciona

  1. IEspecificacion define una expresión; ReservasActivasDelGrupo le da un significado concreto.
  2. El criterio incluye reservas activas del grupo y excluye las canceladas o ajenas.
  3. Sobre objetos ya cargados se compila; en un proveedor compatible se entrega la expresión sin Compile.

Resultado esperado: El grupo ajeno y las reservas canceladas quedan excluidos; verifica SQL por separado.

03

Cuándo usarlo y qué debes evitar

Una regla pura de dominio puede evaluar objetos; una consulta puede incluir orden y límites en una frontera de aplicación o infraestructura. Mantén evaluadores EF fuera del dominio.

Autorizar una cancelación requiere comprobar recurso y actor aunque exista un filtro de listado. Una prueba con Compile no demuestra traducción SQL.

Ampliación opcional · contexto y variantes del tema

Specification Pattern: una consulta con nombre

Una especificación encapsula un criterio que tiene significado y puede reutilizarse. ReservasActivasDelGrupo expresa qué filas interesan; el evaluador decide cómo aplicar el criterio en un proveedor. Para consultas usa Expression<Func<T,bool>> si necesitas traducción SQL; Func<T,bool> es un delegado para ejecutar sobre objetos. Compilar la expresión sirve para la consola, pero no debe introducir evaluación local accidental en una consulta de base de datos.

Una especificación de dominio puede contestar si un objeto cumple una regla sin conocer EF. Una especificación de consulta puede contener filtro, orden y paginación; colócala en una frontera donde esos conceptos pertenezcan. Si incluye relaciones o proyecciones específicas del almacenamiento, no la presentes como regla pura del dominio. El evaluador EF vive en Infraestructura.

El patrón se estudia después de Repository y antes de CQRS: primero reconoces la frontera de datos, luego nombras consultas y después separas responsabilidades de lectura/escritura. No es obligatorio para toda consulta. Una proyección única, sencilla y local puede ser más comprensible expresada directamente. No uses una especificación como única autorización: quien invoca la operación sigue teniendo que verificar actor, acción y recurso.

Especificación mínima del laboratorioC#

Punto de partida No incorpora una biblioteca. Captura un grupo validado y expresa un filtro. En memoria se usa Criterio.Compile(); en un proveedor compatible se usa Where(Criterio) sin compilar.

Antes de ejecutar

Tipos completos compilados en el laboratorio

using System.Linq.Expressions;
public interface IEspecificacion<T>
{
    Expression<Func<T, bool>> Criterio { get; }
}
public sealed class ReservasActivasDelGrupo(string grupoId)
    : IEspecificacion<Reserva>
{
    public Expression<Func<Reserva, bool>> Criterio =>
        r => r.GrupoId == grupoId && !r.Cancelada;
}

Resultado esperado: Incluye una reserva activa del grupo y excluye una cancelada o de otro grupo.

04 · Práctica guiada · opcional

Practica lo aprendido

Prepara tres reservas en memoria: activa del grupo-lima, cancelada del mismo grupo y activa de otro. Aplica la Specification y explica cómo cambiaría la evaluación con IQueryable.

  1. 01Usa Reserva del laboratorio y el fragmento de esta lección para preparar los tres casos.
  2. 02Evalúa el predicado y comprueba que solo la reserva activa del grupo queda incluida.
  3. 03Explica por qué la prueba en memoria no verifica SQL. Como ampliación, prepara EF Core y comprueba la traducción sin Compile.
Ver solución orientativa

El predicado acepta la activa del grupo y rechaza las otras dos. Compile genera un delegado para memoria. Un IQueryable debe recibir la expresión y su proveedor debe poder traducirla; eso requiere una prueba de integración separada.

05

Comprueba lo aprendido

Responde antes de abrir la explicación. Esta comprobación es opcional y no guarda una puntuación.

01¿Una Specification es siempre más clara que LINQ local?

No. Úsala cuando el criterio tenga significado y reutilización.

02¿Qué puedes demostrar en memoria y qué queda pendiente al usar la Specification con EF Core?

En memoria demuestras la lógica del predicado con inclusión y exclusión. EF Core necesita recibir la expresión sin Compile y traducirla con su proveedor; SQL, restricciones y costo requieren otra prueba.

Cómo demostrar el objetivo

Compara tu práctica con estos resultados. Si solo diseñaste una prueba, registra su resultado como esperado, no como observado.

  • El predicado incluye la reserva activa del grupo y excluye la cancelada y la de otro grupo.
  • Distingues Compile para memoria de pasar la expresión a IQueryable y verificar su traducción por separado.

Qué debes recordar

  • Specification nombra un criterio reutilizable.
  • El evaluador determina dónde y cómo se aplica.
Tu cuaderno · notas personales

Cuaderno local

Tus notas del contenido

Se guardan únicamente en este dispositivo. Puedes exportarlas cuando quieras.

Guardado local automático
Material de apoyo · descarga, glosario y referencias
Libro de trabajo · Specification Pattern: criterios y evaluadoresLaboratorio C# · núcleo y 15 comprobaciones

Explicaciones, ejemplos y prácticas propios de Academia de Software. Los fragmentos de integración requieren las dependencias indicadas; el ZIP contiene el núcleo de consola. Las lecturas externas se consultan en su sitio original y conservan sus condiciones. Procedencia y condiciones de uso.