Me tropecé al intentar usar mi especificación dentro de una consulta LINQ. El problema aquí es con mi especificación con params.Especificación dentro de LINQ con EF 4.3
simular un escenario simple Vamos:
public class Car {
public Guid Id { get; set; }
public string Color { get; set; }
public int UsedPieces { get; set; }
// whatever properties
}
public class Piece {
public Guid Id { get; set; }
public string Color { get; set; }
// whatever properties
}
public static class PieceSpecifications : ISpecification<Piece> {
public static ISpecification<Piece> WithColor(string color) {
return new Specification<Piece>(p => p.Color == color);
}
}
lo que estoy realmente tratando de hacer
// Get accepts ISpecification and returns IQueryable<Car> to force just one call to database
var carWithPieces = _carRepository.Get(CarSpecifications.UsedPiecesGreaterThan(10));
var piecesWithColor = from p in _pieceRepository.Get()
let car = carWithPieces.FirstOrDefault() // entire query will does one call to database
where PieceSpecifications.WithColor(car.Color).IsSatisfiedBy(p) // unfortunately it isn't possible
// where p.Color == car.Color -> it works, but it's not what I want
select p;
Sé que es un poco confuso, pero estoy tratando de evitar una gran cantidad de ida y vuelta dentro de mi escenario real (grande) y sé que en realidad es imposible hacerlo usando LINQ sin procesar con el marco de la entidad. Estoy cansado de probar tantos blogs y enfoques fallidos (míos). Alguien sabe algo realmente bueno. Hay otra manera de hacer eso?
Error
System.NotSupportedException: LINQ to Entities no reconoce el método método 'Boolean IsSatisfiedBy (App.Model.Piece)', y este método no se puede traducir en una expresión tienda .
ACTUALIZACIÓN
especificación básica del patrón
public class Specification<T> : ISpecification<T> {
private readonly Expression<Func<T, bool>> _predicate;
public Specification(Expression<Func<T, bool>> predicate) {
_predicate = predicate;
}
public Expression<Func<T, bool>> Predicate {
get { return _predicate; }
}
public bool IsSatisfiedBy(T entity) {
return _predicate.Compile().Invoke(entity);
}
}
ACTUALIZACIÓN
Es bastante fácil ordenada si hago esto
// call to database
var car = _carRepository
.Get(CarSpecifications.UsedPiecesGreaterThan(10))
.FirstOrDefault();
// Whoah! look I'm working, but calling to database again.
var piecesWithColor = _pieceRepository
.Get(PieceSpecifications.WithColor(car.Color))
.ToArray();
Repositorio
// The Get function inside repository accepts ISpecification<T>.
public IQueryable<T> Get(ISpecification<T> specification) {
return Set.Where(specification.Predicate);
}
¿Podría explicar qué * IsSatisfiedBy (p) * hace? – Aducci
Verifique mi publicación, actualicé con una implementación de especificación simple. –
Tienes razón, simplemente no puedes hacerlo. Linq no es tan listo para interpretar tu código personalizado en t-sql. Esperemos .NET 4.5 y EF 5.0 donde con la compatibilidad enum (esta característica se conecta con la pregunta) podemos ver algunos nuevos azúcares de sintaxis. También soy interesante en eso. –