2010-07-02 16 views
8

कृपया अपने डेटाबेस को एक ईएफ n00b डिज़ाइन करने में सहायता करें। मेरे पास कई कंपनियां हैं जो कई उत्पादों का उत्पादन करती हैं, इसलिए कंपनियों और उत्पादों के बीच कई सारे संबंध हैं। मेरे पास एक मध्यवर्ती तालिका है, Company_Product, जो उन्हें संबंधित करता है।इकाई फ्रेमवर्क कई से कई प्रश्न

प्रत्येक कंपनी/उत्पाद संयोजन में एक अद्वितीय एसकेयू है। उदाहरण के लिए Acme विगेट्स में एसकेयू 123 है, लेकिन ओमेगा विगेट्स में एसकेयू 456 है। मैंने एसकेयू को कंपनी_Product इंटरमीडिएट टेबल में एक फ़ील्ड के रूप में जोड़ा।

ईएफ ने कंपनी और कंपनी_Product तालिकाओं के बीच 1: * संबंध के साथ एक मॉडल उत्पन्न किया, और उत्पाद और कंपनी_Product तालिकाओं के बीच एक 1: * संबंध। मैं वास्तव में : कंपनी और उत्पाद के बीच संबंध चाहता हूं। लेकिन, सबसे महत्वपूर्ण बात यह है कि सीधे मॉडल से एसकेयू तक पहुंचने का कोई तरीका नहीं है।

क्या मुझे एसकेयू को अपनी मेज में रखना और एक जॉइन लिखना है, या क्या कोई बेहतर तरीका है?

+0

सब ठीक दिखता है ... आपके मॉडल में 3 इकाइयां होनी चाहिए: कंपनी, उत्पाद, और कंपनी_Product। "मॉडल से सीधे एसकेयू तक पहुंचने का कोई तरीका नहीं है" क्या आपने ctx.Company_Products.First()। SKU की कोशिश की है? –

उत्तर

33

मैं बस सुनिश्चित करने के लिए एक नया VS2010 परियोजना (EFv4) में यह परीक्षण किया है, और यहाँ मैं क्या पाया है:

बीच (Company_Product) में साहचर्य तालिका अन्य तालिकाओं के लिए केवल 2 विदेशी कुंजी है जब (कंपनीआईडी ​​और उत्पाद आईडी), फिर डिजाइनर को सभी 3 टेबल जोड़ना कई रिश्तों को मॉडलिंग करने के लिए समाप्त होता है। यह कंपनी_Product तालिका के लिए भी एक वर्ग उत्पन्न नहीं करता है। प्रत्येक कंपनी के पास एक उत्पाद संग्रह होता है, और प्रत्येक उत्पाद में एक कंपनी संग्रह होता है।

हालांकि, यदि आपकी सहयोगी तालिका (कंपनी_Product) में अन्य फ़ील्ड हैं (जैसे कि एसकेयू, इसकी अपनी प्राथमिक कुंजी, या अन्य वर्णनात्मक फ़ील्ड जैसे दिनांक, विवरण, आदि), तो ईएफ मॉडलर एक अलग वर्ग बनाएगा, और यह जो आपने पहले ही देखा है वह करता है।

मध्य में कक्षा 1: * कंपनी और उत्पाद से संबंधित संबंध खराब नहीं है, और आप अभी भी कुछ आसान प्रश्नों के साथ इच्छित डेटा प्राप्त कर सकते हैं।

// Get all products for Company with ID = 1 
var q = 
    from compProd in context.Company_Product 
    where compProd.CompanyID == 1 
    select compProd.Product; 

यह सच है, यह सिर्फ मॉडल के संबंधों नेविगेट करने के लिए, जब आप पहले से ही अपने इकाई भरी हुई वस्तुओं, उदाहरण के लिए है के रूप में आसान नहीं है, लेकिन है कि क्या डेटा स्तर के लिए है। उन प्रश्नों को समझें जो आपके इच्छित डेटा प्राप्त करते हैं। यदि आप वास्तव में उस मध्यम कंपनी_Product क्लास से छुटकारा पाने के लिए चाहते हैं, और क्लास मॉडल में कई से अधिक प्रतिनिधित्व करते हैं, तो आपको केवल 2 विदेशी कुंजी रखने के लिए कंपनी_Product तालिका को पट्टी करना होगा, और छुटकारा पाएं एसकेयू का।

असल में, मुझे यह नहीं कहना चाहिए कि आपको ऐसा करना है ... आप डिजाइनर में कुछ संपादन करने में सक्षम हो सकते हैं और इसे वैसे भी सेट कर सकते हैं। मैं इसे आज़मा दूंगा और रिपोर्ट करूंगा।

अद्यतन

Company_Product तालिका में SKU रखते हुए (मेरे एफई मॉडल अर्थ 3 वर्गों, नहीं 2 था, यह एक 1 के साथ Company_Payload श्रेणी का निर्माण,: * अन्य 2 तालिकाओं के लिए), मैं करने की कोशिश की कंपनी और उत्पाद के बीच सीधे एक एसोसिएशन जोड़ने के लिए।चरणों मैं पीछा थे:

  • सही कंपनी होने के लिए छोड़ दिया पर डिजाइनर में कंपनी वर्ग पर क्लिक करें
  • जोड़ें> एसोसिएशन
  • सेट "द एंड" (यह पहले से ही होना चाहिए)
  • सेट सही पर उत्पाद को
  • बदलें दोनों multiplicities "* (कई)"
  • नेविगेशन गुण नाम दिया जाना चाहिए "उत्पाद" और "कंपनियों" के लिए
  • मारो ठीक है "अंत"।
  • राइट क्लिक करें> "तालिका मानचित्रण"
  • मॉडल में संघ पर क्लिक करें के तहत "एक मेज जोड़ें या देखने" का चयन करें "Company_Product"
  • मानचित्र कंपनी -> आईडी (बाईं ओर) CompanyID को (दाईं ओर)
  • मानचित्र उत्पाद -> आईडी (बाईं ओर) ProductID के लिए (दाईं ओर)

लेकिन, यह काम नहीं करता। यह यह त्रुटि देता है: त्रुटि 3025: पंक्ति 175 से शुरू होने वाले टुकड़ों को मैप करने में समस्या: तालिका कंपनी उत्पाद के सभी प्रमुख गुणों (Company_Product.SKU) के लिए मैपिंग निर्दिष्ट करना आवश्यक है।

इसलिए कि विशेष संगठन अमान्य है, क्योंकि यह तालिका के रूप में Company_Product का उपयोग करता है, लेकिन एसकेयू फ़ील्ड को किसी भी चीज़ पर मैप नहीं करता है।

इसके अलावा, जब मैं इसका शोध कर रहा था, तो मैं एंटिटी फ्रेमवर्क 4.0 प्राप्तकर्ताओं की पुस्तक से "बेस्ट प्रैक्टिस" टिडबिट में आया (ध्यान दें कि अतिरिक्त फ़ील्ड के साथ एक एसोसिएशन टेबल के लिए, 2 एफके के अलावा, वे अतिरिक्त फ़ील्ड का संदर्भ लेते हैं "पेलोड" के रूप में। आपके मामले में, एसकेयू कंपनी_Product में पेलोड है)।

Best Practice

Unfortunately, a project that starts out with several, payload-free, many-to-many relationships often ends up with several, payload-rich, many-to-many relationships. Refactoring a model, especially late in the development cycle, to accommodate payloads in the many-to-many relationships can be tedious. Not only are additional entities introduced, but the queries and navigation patterns through the relationships change as well. Some developers argue that every many-to-many relationship should start off with some payload, typically a synthetic key, so the inevitable addition of more payload has significantly less impact on the project.

So here's the best practice. If you have a payload-free, many-to-many relationship and you think there is some chance that it may change over time to include a payload, start with an extra identity column in the link table. When you import the tables into your model, you will get two one-to-many relationships, which means the code you write and the model you have will be ready for any number of additional payload columns that come along as the project matures. The cost of an additional integer identity column is usually a pretty small price to pay to keep the model more flexible.

(अध्याय 2. इकाई डेटा मॉडलिंग बुनियादी बातों, 2.4। एक पेलोड के साथ एक बहुत-से-अनेक संबंध मॉडलिंग से)

अच्छी सलाह की तरह लगता है। खासकर जब से आपके पास पहले से ही एक पेलोड (एसकेयू) है।

+0

एक ही सटीक मुद्दे, अच्छा जवाब में चल रहा है। –

2

मैं सिर्फ शमूएल के जवाब के लिए निम्न जोड़ना चाहते हैं:

आप सीधे अनेक-से-अनेक संबंध (पेलोड के साथ) अन्य के लिए, आप उपयोग कर सकते हैं की एक तरफ से क्वेरी करना चाहते हैं निम्नलिखित कोड (इसी उदाहरण का उपयोग करते हुए):

Company c = context.Companies.First(); 
IQueryable<Product> products = c.Company_Products.Select(cp => cp.Product); 

products चर तो Company c रिकॉर्ड के साथ जुड़े सभी Product रिकॉर्ड होगा। आप प्रत्येक उत्पाद के लिए SKU शामिल करना चाहते हैं, तो आप ऐसा तरह एक गुमनाम वर्ग इस्तेमाल कर सकते हैं:

var productsWithSKU = c.Company_Products.Select(cp => new { 
    ProductID = cp.Product.ID, 
    Name = cp.Product.Name, 
    Price = cp.Product.Price, 
    SKU = cp.SKU 
}); 
foreach (var 

तुम इतनी तरह सादगी के लिए केवल पढ़ने के लिए संपत्ति में पहली क्वेरी संपुटित कर सकते हैं:

public partial class Company 
{ 
    public property IQueryable<Product> Products 
    { 
    get { return Company_Products.Select(cp => cp.Product); } 
    } 
} 

आप उस क्वेरी के साथ ऐसा नहीं कर सकते जिसमें एसकेयू शामिल है क्योंकि आप अनाम प्रकार वापस नहीं कर सकते हैं। आपको एक निश्चित कक्षा होना चाहिए, जो आम तौर पर Product कक्षा में गैर-मैप किए गए संपत्ति को जोड़कर या Product से प्राप्त होने वाली एक और कक्षा बनाने के द्वारा किया जाएगा जो एक एसकेयू संपत्ति जोड़ देगा।यदि आप विरासत में कक्षा का उपयोग करते हैं, तो आप इसमें बदलाव नहीं कर पाएंगे और इसे ईएफ द्वारा प्रबंधित किया जाएगा - यह केवल प्रदर्शन उद्देश्यों के लिए उपयोगी होगा।

चीयर्स। :)

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