2012-03-14 10 views
5

के साथ LINQ के अंदर विशिष्टता LINQ क्वेरी के अंदर मैं अपने विनिर्देश का उपयोग करने की कोशिश कर रहा था। यहाँ परेशानी पैराम के साथ मेरे विनिर्देश के साथ है।ईएफ 4.3

आइए नकली एक सरल परिदृश्य:

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 विधि 'बूलियन 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(); 
012 कर

भंडार

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

क्या आप समझा सकते हैं कि * क्या संतुष्ट है (पी) * करता है? – Aducci

+0

मेरी पोस्ट की जांच करें, मैंने एक सरल विनिर्देश कार्यान्वयन के साथ अद्यतन किया। –

+0

आप सही हैं, आप बस इसे नहीं कर सकते हैं। टी-एसक्यूएल में कस्टम कोड की व्याख्या करने के लिए लिंक इतने चालाक नहीं हैं। आइए 4.5 और ईएफ 5.0 के लिए प्रतीक्षा करें जहां enum समर्थन के साथ (यह सुविधा प्रश्न के साथ जुड़ती है) हम कुछ नई वाक्यविन्यास चीनी देख सकते हैं। मैं इसमें भी दिलचस्प हूं। –

उत्तर

1

आप संकलन और अभिव्यक्ति आह्वान आप LINQ करने वाली संस्थाओं क्वेरी में उपयोग करना चाहते हैं, तो नहीं कर सकते। Predicate का उपयोग सीधे करने की कोशिश करें क्योंकि LINQ-to-entities अभिव्यक्ति वृक्ष बनाता है जिसका मूल्यांकन ईएफ LINQ प्रदाता द्वारा किया जाता है और SQL में अनुवाद किया जाता है।

आईएमएचओ विनिर्देश का उपयोग इस तरह से समझ में नहीं आता है। LINQ-to-entities क्वेरी एक समग्र विनिर्देश है। तो या तो लिंक-टू-एंटिटीज का उपयोग करें या विनिर्देश का उपयोग करके अपनी खुद की क्वेरी भाषा बनाएं और अपनी रिपोजिटरी को LINQ क्वेरी में अपनी क्वेरी का अनुवाद दें।

+1

मेरे आवेदन को भविष्यवाणियों का पुन: उपयोग करने की आवश्यकता है और इसलिए मैंने सोचा कि विनिर्देश पैटर्न पूरी तरह से फिट होगा।मैं कल्पना नहीं कर सकता कि कुछ पुन: प्रयोज्य भविष्यवाणियों को कैसे कार्यान्वित किया जाए। –

+0

यदि आप इस तरह की 'कहां' विधि का उपयोग करने का प्रयास करते हैं तो क्या होता है: '। जहां (टुकड़ा स्पेसिफिकेशंस.कॉलर (कार। रंग)। भविष्यवाणी करें? –

+1

मैं ऐसा नहीं कर सकता क्योंकि क्वेरी के अंदर 'कार' घोषित किया गया है। 'कार = carWithPieces.FirstOrDefault() 'चलो। जैसे मैंने कहा, मैं roundtrips से बचने की कोशिश कर रहा हूँ। –

1

AsExpandable एक्सटेंशन विधि का उपयोग करने पर एक नज़र डालें।

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

+0

LINQKit वास्तव में LINQ से इकाइयों का एक बड़ा हिस्सा बढ़ाता है, लेकिन मुझे 'टुकड़ा स्पेसिफिकेशंस.कॉलर (कार। रंग) काम करने का कोई तरीका नहीं मिल रहा है। भविष्यवाणी। इन्वोक (पी) '। दुर्भाग्यवश ऐसा लगता है कि LINQKit पैराकॉलर जैसे पैराम के साथ एक विधि का समर्थन नहीं करता है। फिर भी धन्यवाद। –

0

शायद IsSatisfiedBy बनाने के() और IQueryable के लिए विस्तार विधि। यहां के। स्कॉट एलन का दृष्टिकोण है: http://odetocode.com/Blogs/scott/archive/2012/03/19/avoiding-notsupportedexception-with-iqueryable.aspx

+0

यह एक और परिदृश्य है। समस्या किसी अन्य प्रकार (डीटीओ) के साथ संग्रह का चयन करने के बारे में नहीं है। शायद यह किसी के लिए सहायक होगा। धन्यवाद। –