2016-01-21 6 views
6

मैं Include के साथ अपनी क्वेरी में नेविगेशन प्रॉपर्टी भी शामिल कर रहा हूं, ताकि बाद में आलसी लोड न हो। लेकिन यह काम नहीं करता है, जब मैं Select प्रोजेक्शन के साथ एक अनाम रैपर-ऑब्जेक्ट बनाता हूं।ईएफ: "चयन करें" प्रक्षेपण के साथ एक रैपर ऑब्जेक्ट बनाते समय नेविगेशन प्रॉपर्टी को "शामिल करें"

मुझे सरलीकृत उदाहरण दिखाएं। इकाई:

public class UserEntity { 
    public string Name {get;set;} 
    public virtual ICollection<UserEntity> Friends { get; set; } 
} 

क्वेरी:

var entry = _dbCtx 
    .Users 
    .Include(x => x.Friends) 
    // Select here is simplified, but it shows the wrapping 
    .Select(user => new { 
     User = user 
    }) 
    .First(); 

// Here we have additional lazy loaded DB call 
var friends = entry.User.Friends.Select(x => x.Name).ToList(); 

और मैं उत्पन्न एसक्यूएल से भी देखते हैं, कि नेविगेशन संपत्ति शामिल नहीं है:

SELECT 
    [Limit1].[Name] AS [Name], 
    FROM (SELECT TOP (1) 
     [Extent1].[Name] AS [Name] 
     FROM [dbo].[Users] AS [Extent1] 
    ) AS [Limit1] 

क्या यह संभव है Include नेविगेशन प्रॉपर्टी Friends में इस मामले में, User आलसी लोडिंग के बिना डेटा प्राप्त होगा?

मैं भी उम्मीद कर रहा था यह काम करने के लिए:

var entry = _dbCtx 
    .Users 
    .Select(user => new { 
     User = user 
    }) 
    .Include(x => x.User.Friends) 
    .First(); 

लेकिन एक अपवाद हो रही:

InvalidOperationException: क्वेरी के परिणाम प्रकार का न तो कोई EntityType है और न ही एक इकाई तत्व प्रकार के साथ एक CollectionType है । एक समावेश पथ केवल इन परिणामों में से किसी एक के साथ एक क्वेरी के लिए निर्दिष्ट किया जा सकता है। एक करने के लिए उपयोगकर्ता

var entry = _dbCtx 
    .Users 
    .Select(user => new { 
     User = user, 
     UsersFriends = user.Friends 
    }) 
    .First(); 

// manually copy the navigation property 
entry.User.Friends = user.UsersFriends; 

// Now we don't have any addition queries 
var friends = entry.User.Friends.Select(x => x.Name).ToList(); 
  • मानचित्र भी:

  • कुछ समाधान मैं के लिए आया था रहे हैं, लेकिन वे किसी भी तरह मुश्किल कर रहे हैं:

    1. Select में हमारे गुमनाम वस्तु के अलावा संपत्ति जोड़ें डीबी स्तर पर अज्ञात ऑब्जेक्ट, और उसके बाद C# में UserEntity पर गुण गुण।

      var entry = _dbCtx 
          .Users 
          .Select(user => new { 
           User = new { 
            Name = user.Name, 
            Friends = user.Friends 
           } 
          }) 
          .Take(1) 
          // Fetch the DB 
          .ToList() 
          .Select(x => new { 
           User = new UserEntity { 
            Name = x.Name, 
            Friends = x.Friends 
           } 
          }) 
          .First(); 
      
      // Now we don't have any addition queries 
      var friends = entry.User.Friends.Select(x => x.Name).ToList(); 
      

    तो अब, वहाँ Friends के लिए एक LEFT OUTER JOIN है, लेकिन दोनों समाधानों काफी अच्छा नहीं कर रहे हैं:

    1) अतिरिक्त गुण और एक प्रति एक साफ रास्ता नहीं है।

    2) मेरे उपयोगकर्ता एंटिटी के पास अन्य कई गुण हैं। इसके अतिरिक्त, हर बार जब हम नई संपत्तियां जोड़ते हैं, तो हमें यहां चयनकर्ताओं को भी संशोधित करना चाहिए।

    क्या पहले नमूने सहित नेविगेशन संपत्ति प्राप्त करने का कोई तरीका है?

    पढ़ने के लिए धन्यवाद और मुझे आशा है कि किसी के पास इसके लिए एक सुराग है।

    संपादित करें:

    मैं एक असली यूज-केस को दिखाने के लिए इकाई और क्वेरी का विस्तार होगा।

    इकाई

    public class UserEntity { 
        public string Name {get;set;} 
        public int Score {get;set;} 
        public virtual ICollection<UserEntity> Friends { get; set; } 
    } 
    

    क्वेरी

    var entry = _dbCtx 
        .Users 
        .Include(x => x.Friends) 
        .Select(user => new { 
         User = user, 
         Position = _dbCtx.Users.Count(y => y.Score > user.Score) 
        }) 
        .First(); 
    

    उत्तर

    0

    नहीं _why_ के रूप में एक जवाब लेकिन बेहतर कोड स्वरूपण चाहता था ...

    मैं वास्तव में हूँ आश्चर्य है कि यह उस तरह से काम करता है। शायद ईएफ यह पता लगा रहा है कि आप सीधे अपने प्रक्षेपण में Friends संपत्ति का उपयोग नहीं कर रहे हैं और इस प्रकार इसे अनदेखा कर रहे हैं। क्या होगा यदि आप एफई क्वेरी की बाहर वस्तु (रों) समझाया:

    var entry = _dbCtx 
        .Users 
        .Include(x => x.Friends) 
        .Take(1); // replicate "First" inside the EF query to reduce traffic 
        .AsEnumerable() // shift to linq-to-objects 
        // Select here is simplified, but it shows the wrapping 
        .Select(user => new { 
         User = user 
        }) 
        .First() 
    
    +0

    के रूप में हम 'ग #' पक्ष (क्वेरी के बाद) पर एक आवरण वस्तु बनाने आपका नमूना काम करेंगे, 'sql' नहीं के साथ। लेकिन मुझे इसे 'डीबी' स्तर पर चाहिए था। कारण: मैं 'चयन' के साथ अतिरिक्त सबक्वायरी करता हूं। दिलचस्प बात, मेरा पहला कामकाज देखें, हालांकि हम क्वेरी में 'user.Friends' का उपयोग करते हैं, लेकिन हमें भौतिकरण के बाद संपत्ति को वापस इकाई में कॉपी करना होगा, अन्यथा हम अभी भी आलसी लोडिंग करेंगे। – tenbits

    +0

    आपको डीबी क्वेरी में किसी अनाम प्रकार को प्रोजेक्ट करने की आवश्यकता क्यों है? जहां तक ​​मैं कह सकता हूं आप उसी परिणाम के साथ समाप्त हो जाते हैं। या आप _additional_ विधियों ('कहां', 'ऑर्डरबी', आदि) पेश कर रहे हैं जिन्हें आप एसक्यूएल में प्रोजेक्ट करना चाहते हैं? –

    +0

    मेरे पोस्ट संपादन देखें, मैं उपयोगकर्ता के लिए एक सबक्वायरी करता हूं, और इसे डीबी में किया जाना चाहिए, क्योंकि यह प्रत्येक उपयोगकर्ता पर पुनरावृत्त होता है। तो प्रदर्शन के कारण, मैं इसे 'C#' के साथ नहीं कर सकता। – tenbits

    संबंधित मुद्दे