带EF 4.3的LINQ内部规范
本文关键字:内部 LINQ EF | 更新日期: 2023-09-27 18:27:53
我在LINQ查询中使用规范时遇到了麻烦。这里的问题是我的params规范。
让我们伪造一个简单的场景:
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);
}
}
// 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;
我知道这有点令人困惑,但我试图在我的真实(大)场景中避免很多往返,我知道实际上不可能使用带有实体框架的原始LINQ。我厌倦了尝试这么多博客和失败的(我的)方法。有人知道一些真正好的方法。还有别的办法吗?
错误
System.NotSupportedException:LINQ to Entities不识别method"Boolean IsSatisfiedBy(App.Model.Piece)"方法,并且方法无法转换为存储表达式。
更新
基本规范模式
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);
}
}
更新
如果我做这个,那就很容易了
// 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();
存储库
// The Get function inside repository accepts ISpecification<T>.
public IQueryable<T> Get(ISpecification<T> specification) {
return Set.Where(specification.Predicate);
}
如果要在LINQ to实体查询中使用表达式,则不能编译和调用它。尝试直接使用Predicate
,因为LINQ to实体会构建表达式树,该表达式树由EF LINQ提供程序评估并转换为SQL。
IMHO以这种方式使用规范是没有意义的。LINQ到实体查询是一个复合规范。所以,使用Linq来实体,或者使用规范构建自己的查询语言,并让您的存储库将您的查询转换为Linq查询。
看看使用AsExpandable扩展方法。
http://www.albahari.com/nutshell/linqkit.aspx
也许可以将IsSatisfiedBy()和扩展方法设置为IQueryable。以下是K.Scott Allen的方法:http://odetocode.com/Blogs/scott/archive/2012/03/19/avoiding-notsupportedexception-with-iqueryable.aspx