2012-03-14 30 views
5

Tôi tình cờ cố gắng sử dụng đặc tả của tôi bên trong truy vấn LINQ. Vấn đề ở đây là với đặc điểm kỹ thuật của tôi với các thông số.Đặc điểm kỹ thuật bên trong LINQ với EF 4.3

giả một kịch bản đơn giản Hãy:

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); 
    } 
} 

những gì tôi đang thực sự cố gắng để làm

// 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; 

Tôi biết đó là một chút khó hiểu, nhưng tôi đang cố gắng để tránh được rất nhiều roundtrips bên trong kịch bản thực sự (lớn) của tôi và tôi biết rằng thực sự nó không thể làm bằng cách sử dụng LINQ thô với khung thực thể. Tôi cảm thấy mệt mỏi khi thử nhiều blog và phương pháp tiếp cận thất bại. Có người biết cách tiếp cận thực sự tốt. Có một cách khác để làm điều đó?

Lỗi

System.NotSupportedException: LINQ to Entities không nhận ra phương pháp 'Boolean IsSatisfiedBy (App.Model.Piece)' phương pháp, phương pháp và này không thể được dịch sang một biểu hiện cửa hàng .

CẬP NHẬT

cơ bản Thông số kỹ thuật Pattern

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); 
    } 
} 

CẬP NHẬT

Nó khá dễ dàng gọn gàng nếu tôi làm điều này

// 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(); 

Repository

// The Get function inside repository accepts ISpecification<T>. 
public IQueryable<T> Get(ISpecification<T> specification) { 
    return Set.Where(specification.Predicate); 
} 
+1

Bạn có thể giải thích những gì * IsSatisfiedBy (p) * làm không? – Aducci

+0

Kiểm tra bài đăng của tôi, tôi đã cập nhật với triển khai thông số kỹ thuật đơn giản. –

+0

Bạn nói đúng, bạn không thể làm được. LINQ không thông minh lắm để giải thích mã tùy chỉnh của bạn thành t-sql. Cho phép đợi .Net 4.5 và EF 5.0 với hỗ trợ enum (tính năng này kết nối với câu hỏi), chúng ta có thể thấy một số đường cú pháp mới. Tôi cũng rất thú vị. –

Trả lời

1

Bạn không thể biên dịch và gọi biểu hiện nếu bạn muốn sử dụng nó trong LINQ-to-thực thể truy vấn. Cố gắng sử dụng trực tiếp Predicate vì LINQ-to-entity xây dựng cây biểu thức được đánh giá bởi nhà cung cấp LINQ EF và được dịch sang SQL.

Đặc điểm kỹ thuật sử dụng IMHO theo cách này không có ý nghĩa. Truy vấn LINQ-to-entity là một đặc tả tổng hợp. Vì vậy, hoặc sử dụng LINQ-to-thực thể hoặc xây dựng ngôn ngữ truy vấn của bạn bằng cách sử dụng đặc điểm kỹ thuật và để kho lưu trữ của bạn dịch truy vấn của bạn để truy vấn LINQ.

+1

Ứng dụng của tôi yêu cầu sử dụng lại các biến vị ngữ và đó là lý do tại sao tôi nghĩ rằng mẫu đặc tả sẽ phù hợp hoàn hảo.Tôi không thể tưởng tượng làm thế nào để thực hiện một số predicates tái sử dụng. –

+0

Điều gì xảy ra nếu bạn thử sử dụng phương thức 'Where' mở rộng như sau:' .Where (PieceSpecifications.WithColor (car.Color) .Predicate) 'thay thế? –

+1

Tôi không thể làm điều đó vì 'xe' được khai báo bên trong truy vấn. 'let car = carWithPieces.FirstOrDefault()'. Như tôi đã nói, tôi đang cố tránh những chuyến đi khứ hồi. –

1

Hãy xem xét sử dụng phương pháp tiện ích mở rộng AsExpandable.

http://www.albahari.com/nutshell/linqkit.aspx

+0

LINQKit thực sự mở rộng một phần lớn của LINQ to Entities, nhưng tôi không thể tìm thấy một cách để hoạt động 'PieceSpecifications.WithColor (car.Color) .Predicate.Invoke (p)'. Thật không may có vẻ như LINQKit không hỗ trợ một phương thức với các tham số, như WithColor. Dù sao cũng cảm ơn bạn. –

Các vấn đề liên quan