यह पोस्ट दिखाता है कि अत्यधिक सामान्यीकृत SQL डेटाबेस को कैसे क्वेरी करें , और परिणाम को अत्यधिक नेस्टेड C # POCO ऑब्जेक्ट के सेट में मैप करें।
सामग्री:
- C # की 8 लाइनें।
- कुछ यथोचित सरल SQL जो कुछ जोड़ का उपयोग करता है।
- दो भयानक पुस्तकालय।
अंतर्दृष्टि जो मुझे इस समस्या को हल करने की अनुमति देती है, उससे अलग होना MicroORM
है mapping the result back to the POCO Entities
। इस प्रकार, हम दो अलग-अलग पुस्तकालयों का उपयोग करते हैं:
अनिवार्य रूप से, हम डेटाबेस को क्वेरी करने के लिए डैपर का उपयोग करते हैं, फिर परिणाम को सीधे हमारे पीओओ में मैप करने के लिए स्लैपर.एटोमैपर का उपयोग करते हैं।
लाभ
- सादगी । इसकी 8 से कम लाइनें हैं। मुझे यह समझने, बहस करने और बदलने में बहुत आसान लगता है।
- कम कोड । कोड की कुछ पंक्तियाँ सभी Slapper.Automapper को आपके द्वारा फेंके गए किसी भी चीज़ को संभालने की आवश्यकता होती हैं, भले ही हमारे पास एक जटिल नेस्टेड POCO हो (यानी POCO जिसमें
List<MyClass1>
बदले में शामिल हैं List<MySubClass2>
, आदि)।
- गति । इन दोनों पुस्तकालयों के पास अनुकूलन और कैशिंग की एक असाधारण राशि है जो उन्हें लगभग इतनी ही तेजी से चलाते हैं जैसे कि ADO.NET प्रश्न।
- चिंताओं का पृथक्करण । हम एक अलग के लिए MicroORM को बदल सकते हैं, और मैपिंग अभी भी काम करता है, और इसके विपरीत।
- लचीलापन । Slapper.Automapper मनमाने ढंग से नेस्टेड पदानुक्रमों को संभालता है, यह नेस्टिंग के स्तर के एक जोड़े तक सीमित नहीं है। हम आसानी से तेजी से बदलाव कर सकते हैं, और सब कुछ अभी भी काम करेगा।
- डिबगिंग । हम पहले देख सकते हैं कि SQL क्वेरी ठीक से काम कर रही है, तो हम जाँच सकते हैं कि SQL क्वेरी परिणाम ठीक से लक्ष्य POCO संगठनों के लिए मैप किया गया है।
- SQL में विकास में आसानी । मुझे लगता है कि
inner joins
फ्लैट परिणामों को वापस करने के साथ चपटा प्रश्न बनाना कई चुनिंदा बयानों को बनाने की तुलना में बहुत आसान है, क्लाइंट साइड पर सिलाई के साथ।
- एसक्यूएल में अनुकूलित प्रश्नों । एक उच्च सामान्यीकृत डेटाबेस में, एक फ्लैट क्वेरी बनाने से SQL इंजन पूरे में उन्नत अनुकूलन लागू करने की अनुमति देता है जो सामान्य रूप से संभव नहीं होगा यदि कई छोटे व्यक्तिगत प्रश्नों का निर्माण और रन किया गया हो।
- भरोसा है । डैपर स्टैकऑवरफ्लो के लिए अंतिम छोर है, और, ठीक है, रैंडी बर्डन एक सुपरस्टार का एक सा है। मुझे कोई और कहना चाहिए?
- विकास की गति। मैं घोंसले के कई स्तरों के साथ कुछ असाधारण जटिल प्रश्न करने में सक्षम था, और देव समय काफी कम था।
- कम कीड़े। मैंने इसे एक बार लिखा था, यह सिर्फ काम किया, और यह तकनीक अब एक एफटीएसई कंपनी को बिजली देने में मदद कर रही है। इतना कम कोड था कि कोई अप्रत्याशित व्यवहार नहीं था।
नुकसान
- 1,000,000 पंक्तियों से परे स्केलिंग लौट आई। लौटने पर अच्छी तरह से काम करता है <100,000 पंक्तियों। हालाँकि, अगर हम हमारे और SQL सर्वर के बीच ट्रैफ़िक को कम करने के लिए, 1,000,000 पंक्तियों को वापस ला रहे हैं, तो हमें इसका उपयोग करके इसे समतल नहीं करना चाहिए
inner join
(जो डुप्लिकेट वापस लाता है), हमें इसके बजाय कई select
स्टेटमेंट्स का उपयोग करना चाहिए और सब कुछ एक साथ वापस करना चाहिए ग्राहक पक्ष (इस पृष्ठ पर अन्य उत्तर देखें)।
- यह तकनीक क्वेरी ओरिएंटेड है । मैंने डेटाबेस में लिखने के लिए इस तकनीक का उपयोग नहीं किया है, लेकिन मुझे यकीन है कि डैपर कुछ और अतिरिक्त कार्यों के साथ ऐसा करने में सक्षम है, क्योंकि स्टैकओवरफ़्लो स्वयं डैपर को अपने डेटा एक्सेस लेयर (डीएएल) के रूप में उपयोग करता है।
प्रदर्शन का परीक्षण
मेरे परीक्षणों में, Slapper.Automapper ने Dapper द्वारा लौटाए गए परिणामों में एक छोटा ओवरहेड जोड़ा, जिसका अर्थ था कि यह अभी भी एंटिटी फ्रेमवर्क की तुलना में 10x तेज था, और संयोजन अभी भी सैद्धांतिक अधिकतम गति एसक्यूएल # C के करीब सुंदर है ।
अधिकांश व्यावहारिक मामलों में, अधिकांश ओवरहेड एक कम-से-इष्टतम SQL क्वेरी में होगा, और सी # साइड पर परिणामों के कुछ मानचित्रण के साथ नहीं।
प्रदर्शन परीक्षण के परिणाम
पुनरावृत्तियों की कुल संख्या: 1000
Dapper by itself
: 1.889 मिलीसेकंड प्रति क्वेरी, का उपयोग करते हुए 3 lines of code to return the dynamic
।
Dapper + Slapper.Automapper
: 2.463 मिलीसेकंड प्रति क्वेरी, एक अतिरिक्त का उपयोग करके 3 lines of code for the query + mapping from dynamic to POCO Entities
।
काम किया उदाहरण
इस उदाहरण में, हमारे पास सूची है Contacts
, और प्रत्येक Contact
में एक या अधिक हो सकते हैं phone numbers
।
POCO एंटिटीज
public class TestContact
{
public int ContactID { get; set; }
public string ContactName { get; set; }
public List<TestPhone> TestPhones { get; set; }
}
public class TestPhone
{
public int PhoneId { get; set; }
public int ContactID { get; set; }
public string Number { get; set; }
}
एसक्यूएल टेबल TestContact
एसक्यूएल टेबल TestPhone
ध्यान दें कि इस तालिका में एक विदेशी कुंजी है ContactID
जो TestContact
तालिका को संदर्भित करती है (यह List<TestPhone>
ऊपर POCO में मेल खाती है )।
SQL जो फ्लैट परिणाम का उत्पादन करता है
हमारी SQL क्वेरी में, हम उतने ही JOIN
स्टेटमेंट्स का उपयोग करते हैं, जितने की हमें जरूरत है, एक फ्लैट, डिनॉमिनेटेड फॉर्म में सभी डेटा प्राप्त करने के लिए । हां, यह आउटपुट में डुप्लिकेट का उत्पादन कर सकता है, लेकिन जब हम Slapper.Automapper का उपयोग करते हैं, तो ये डुप्लिकेट स्वचालित रूप से समाप्त हो जाएंगे , इस क्वेरी के परिणाम को सीधे हमारे POCO ऑब्जेक्ट मैप में मैप करने के लिए।
USE [MyDatabase];
SELECT tc.[ContactID] as ContactID
,tc.[ContactName] as ContactName
,tp.[PhoneId] AS TestPhones_PhoneId
,tp.[ContactId] AS TestPhones_ContactId
,tp.[Number] AS TestPhones_Number
FROM TestContact tc
INNER JOIN TestPhone tp ON tc.ContactId = tp.ContactId
सी # कोड
const string sql = @"SELECT tc.[ContactID] as ContactID
,tc.[ContactName] as ContactName
,tp.[PhoneId] AS TestPhones_PhoneId
,tp.[ContactId] AS TestPhones_ContactId
,tp.[Number] AS TestPhones_Number
FROM TestContact tc
INNER JOIN TestPhone tp ON tc.ContactId = tp.ContactId";
string connectionString =
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
{
dynamic test = conn.Query<dynamic>(sql);
Slapper.AutoMapper.Configuration.AddIdentifiers(typeof(TestContact), new List<string> { "ContactID" });
Slapper.AutoMapper.Configuration.AddIdentifiers(typeof(TestPhone), new List<string> { "PhoneID" });
var testContact = (Slapper.AutoMapper.MapDynamic<TestContact>(test) as IEnumerable<TestContact>).ToList();
foreach (var c in testContact)
{
foreach (var p in c.TestPhones)
{
Console.Write("ContactName: {0}: Phone: {1}\n", c.ContactName, p.Number);
}
}
}
}
उत्पादन
POCO इकाई पदानुक्रम
Visual Studio में देखते हुए, हम देख सकते हैं कि Slapper.Automapper ने हमारे POCO Entities को अच्छी तरह से आबाद किया है, अर्थात हमारे पास एक है List<TestContact>
, और प्रत्येक TestContact
में एक है List<TestPhone>
।
टिप्पणियाँ
Dapper और Slapper.Automapper दोनों गति के लिए आंतरिक रूप से सब कुछ कैश करते हैं। यदि आप मेमोरी मुद्दों (बहुत ही असंभावित) में चलते हैं, तो सुनिश्चित करें कि आप कभी-कभी उन दोनों के लिए कैश को साफ़ करें।
सुनिश्चित करें कि आप वापस आने वाले स्तंभों को नाम देते हैं, जो कि Slapper.Automapper सुराग देने के लिए अंडरस्कोर ( _
) संकेतन का उपयोग करके POCO संस्थाओं में परिणाम को मैप करते हैं।
सुनिश्चित करें कि आप Slapper.Automapper सुराग प्रत्येक POCO इकाई (लाइनों देखें Slapper.AutoMapper.Configuration.AddIdentifiers
) के लिए प्राथमिक कुंजी पर दे । आप इसके Attributes
लिए POCO पर भी उपयोग कर सकते हैं । यदि आप इस चरण को छोड़ देते हैं, तो यह गलत हो सकता है (सिद्धांत रूप में), जैसा कि Slapper.Automapper को नहीं पता होगा कि मैपिंग ठीक से कैसे करें।
अद्यतन 2015-06-14
40 से अधिक सामान्यीकृत तालिकाओं के साथ एक विशाल उत्पादन डेटाबेस के लिए इस तकनीक को सफलतापूर्वक लागू किया। यह 16 से अधिक inner join
और left join
उचित POCO पदानुक्रम (नेस्टिंग के 4 स्तरों के साथ) में एक उन्नत SQL क्वेरी को मैप करने के लिए पूरी तरह से काम करता है । प्रश्न तेजी से अंधा कर रहे हैं, लगभग उपवास के रूप में ADO.NET में कोडिंग (यह आमतौर पर क्वेरी के लिए 52 मिलीसेकंड था, और POCO पदानुक्रम में फ्लैट परिणाम से मानचित्रण के लिए 50 मिलीसेकंड)। यह वास्तव में क्रांतिकारी कुछ भी नहीं है, लेकिन यह सुनिश्चित करता है कि गति और उपयोग में आसानी के लिए एंटिटी फ्रेमवर्क धड़कता है, खासकर अगर हम जो कर रहे हैं वह सभी प्रश्न चल रहे हैं।
अपडेट 2016-02-19
कोड उत्पादन में 9 महीनों से दोषपूर्ण तरीके से चल रहा है। नवीनतम संस्करण में Slapper.Automapper
उन सभी परिवर्तनों को शामिल किया गया है जो मैंने SQL क्वेरी में दिए जा रहे नल से संबंधित समस्या को ठीक करने के लिए लागू किया था।
अद्यतन 2017-02-20
कोड 21 महीनों से उत्पादन में दोषपूर्ण तरीके से चल रहा है, और एक FTSE 250 कंपनी में सैकड़ों उपयोगकर्ताओं से निरंतर प्रश्नों को संभाला है।
Slapper.Automapper
POCO की सूची में सीधे .csv फ़ाइल की मैपिंग के लिए भी बढ़िया है। IDv की सूची में .csv फ़ाइल पढ़ें, फिर इसे सीधे POCOs की लक्ष्य सूची में मैप करें। एकमात्र चाल यह है कि आपको एक उचित जोड़ना होगा int Id {get; set}
, और यह सुनिश्चित करना होगा कि यह प्रत्येक पंक्ति के लिए अद्वितीय है (या फिर ऑटोमेपर पंक्तियों के बीच अंतर करने में सक्षम नहीं होगा)।
अपडेट 2019-01-29
अधिक कोड टिप्पणियाँ जोड़ने के लिए मामूली अद्यतन।
देखें: https://github.com/SlapperAutoMapper/Slapper.AutoMapper