मैं 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();
मानचित्र भी:
कुछ समाधान मैं के लिए आया था रहे हैं, लेकिन वे किसी भी तरह मुश्किल कर रहे हैं:
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();
के रूप में हम 'ग #' पक्ष (क्वेरी के बाद) पर एक आवरण वस्तु बनाने आपका नमूना काम करेंगे, 'sql' नहीं के साथ। लेकिन मुझे इसे 'डीबी' स्तर पर चाहिए था। कारण: मैं 'चयन' के साथ अतिरिक्त सबक्वायरी करता हूं। दिलचस्प बात, मेरा पहला कामकाज देखें, हालांकि हम क्वेरी में 'user.Friends' का उपयोग करते हैं, लेकिन हमें भौतिकरण के बाद संपत्ति को वापस इकाई में कॉपी करना होगा, अन्यथा हम अभी भी आलसी लोडिंग करेंगे। – tenbits
आपको डीबी क्वेरी में किसी अनाम प्रकार को प्रोजेक्ट करने की आवश्यकता क्यों है? जहां तक मैं कह सकता हूं आप उसी परिणाम के साथ समाप्त हो जाते हैं। या आप _additional_ विधियों ('कहां', 'ऑर्डरबी', आदि) पेश कर रहे हैं जिन्हें आप एसक्यूएल में प्रोजेक्ट करना चाहते हैं? –
मेरे पोस्ट संपादन देखें, मैं उपयोगकर्ता के लिए एक सबक्वायरी करता हूं, और इसे डीबी में किया जाना चाहिए, क्योंकि यह प्रत्येक उपयोगकर्ता पर पुनरावृत्त होता है। तो प्रदर्शन के कारण, मैं इसे 'C#' के साथ नहीं कर सकता। – tenbits