2015-09-15 8 views
8

तालिका प्रति पदानुक्रम (टीपीएच) के उपयोग से बचने के प्रयास में मैं तालिका-प्रति-कंक्रीट कक्षा को सर्वोत्तम तरीके से कार्यान्वित करने के उदाहरणों को देख रहा हूं (टीपीसी) मेरे डेटाबेस मॉडल में विरासत। मैं official documentation और this article भर में आया था।तालिका प्रति कंक्रीट प्रकार (टीपीसी) प्रविष्टि फ्रेमवर्क 6 (ईएफ 6)

नीचे कुछ सरल विरासत वाले कुछ नकली वर्ग हैं।

public class BaseEntity 
{ 
    public BaseEntity() 
    { 
     ModifiedDateTime = DateTime.Now; 
    } 

    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 

    public DateTime ModifiedDateTime { get; set; } 
} 

public class Person : BaseEntity 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

public class Business : BaseEntity 
{ 
    public string Name { get; set; } 
    public string Location { get; set; } 
} 

डीबीमोडेलबिल्डर कॉन्फ़िगरेशन दोनों लेखों में उदाहरणों के अनुसार उपयोग किया जाता है।

modelBuilder.Entity<BaseEntity>() 
    .Property(c => c.Id) 
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 

modelBuilder.Entity<Person>().Map(m => 
{ 
    m.MapInheritedProperties(); 
    m.ToTable("Person"); 
}); 

modelBuilder.Entity<Business>().Map(m => 
{ 
    m.MapInheritedProperties(); 
    m.ToTable("Business"); 
}); 

आवेदन सफलतापूर्वक चलता लेकिन जब मैं डेटाबेस के लिए वापस जाओ मैं तीन (3) के बजाय दो (2) मुझे लगता है की उम्मीद कर टेबल पाते हैं। कुछ परीक्षण के बाद यह "बेसइन्टिटी" तालिका दिखाई देगी लेकिन इसका कभी भी उपयोग नहीं किया जाता है। सब कुछ खाली अनाथ टेबल के अपवाद के साथ बस ठीक काम करता प्रतीत होता है।

मैं डीबीमोडेलबिल्डर कॉन्फ़िगरेशन के साथ गड़बड़ करता हूं, अंत में "बेसएन्टीटी" कॉन्फ़िगरेशन को हटा देता हूं जो अपेक्षित परिणाम प्रदान करता है; दो (2) टेबल, उनमें से प्रत्येक सही गुण और सही ढंग से काम कर रहा है।

मैं एक आखिरी परीक्षण करता हूं, सभी डीबीमोडेलबिल्डर कॉन्फ़िगरेशन को चीरता हूं, केवल "व्यक्ति" और "व्यवसाय" के लिए दो (2) डीबीसेट गुणों को शामिल करता है और फिर परीक्षण करता है।

public DbSet<Person> People { get; set; } 
public DbSet<Business> Businesses { get; set; } 

मेरे आश्चर्य परियोजना बनाता करने के लिए, चला जाता है डेटाबेस के लिए बाहर, सभी वर्ग "BaseEntity" वर्ग से विरासत में मिला भी शामिल होते हैं गुणों के साथ केवल दो तालिकाओं बनाता है। मैं बिना किसी मुद्दे के सीआरयूडी परिचालन कर सकता हूं।

कई परीक्षण चलाने के बाद मुझे अंतिम परीक्षण के साथ कोई समस्या नहीं मिल रही है और मैं दोनों लेखों के बारे में चेतावनी दी गई डुप्लिकेट कुंजी त्रुटि को पुन: उत्पन्न करने में सक्षम नहीं हूं।

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

  1. मैं क्यों उदाहरण MapInheritedProperties संपत्ति का उपयोग उत्सुक हूँ; क्या यह पुरानी विधि है?
  2. दोनों उदाहरणों में "बेसइन्टिटी" के लिए कॉन्फ़िगरेशन गुणों को शामिल करने का कहना क्यों है, फिर भी "बेसइन्टिटी" श्रेणी के लिए या तो डीबीसेट संपत्ति या किसी भी DbModelBuilder कॉन्फ़िगरेशन सहित किसी अप्रयुक्त तालिका को बनाने का कारण बनता है।
  3. अद्वितीय कुंजी त्रुटि के संदर्भ में लेखों की चेतावनी दी गई है; मैं त्रुटि को पुन: उत्पन्न करने में असमर्थ हूं और मैंने प्राथमिक कुंजी के साथ कई बार परीक्षण किया है या तो डेटाबेस द्वारा उत्पन्न एक int और डेटाबेस द्वारा उत्पन्न एक guid। क्या इस त्रुटि के बारे में जानकारी भी अप्रचलित है या क्या कोई परीक्षण है जिसे मैं त्रुटि उत्पन्न करने के लिए चला सकता हूं?
+0

मुझे लगता है कि 3 टेबल बनाए जाने चाहिए, हालांकि आधार एक अनुपयोगी लगता है। यह टीपीसी का कुछ प्रकार का विपक्ष है, आप क्लाइंट कोड में कुछ लाभ ले सकते हैं लेकिन कुछ अनावश्यक डेटा भुगतना होगा (जिसे पारंपरिक डेटाबेस डिज़ाइन अवधारणा के रूप में भी नहीं बनाया जाना चाहिए)। मुझे लगता है कि आप इसके बजाय टीपीटी आज़मा सकते हैं जबकि बेस टेबल में सभी सामान्य कॉलम होते हैं और इसे अब अनावश्यक नहीं माना जाएगा। – Hopeless

+1

@ होपलेस, जिस कारण से मैंने टीपीटी नहीं माना है, उतना ही जितना मैं डिजाइन पहलू को ओसीडी की तरह प्यार करता हूं, वह प्रदर्शन है जो आप थोड़ा सा जटिल डेटा वापस खींचने के लिए आवश्यक सभी शामिल बयानों से प्राप्त होता है। 3 टेबलों के बारे में बयान के लिए, मैंने इसके विपरीत कई लेख देखे हैं लेकिन फिर से कोई भी मैं सही तरीके से काम नहीं कर सकता था। मैं सोच रहा हूं कि मॉडल सेट अप करने के अंतिम तरीके से कुछ नुकसान होता है; मैं दो तालिकाओं के साथ समाप्त हुआ, कोई जंक टेबल नहीं, कोई जंक कॉलम नहीं, कोई प्राथमिक कुंजी समस्या नहीं है, फिर भी मुझे ऐसा करने के लिए कोई उदाहरण नहीं मिल रहा है जो मैंने किया था। – Nicholas

+0

टीपीएच के लिए, बेसइन्टिटी क्लास सार होना चाहिए। मुझे लगता है कि अकेले ठोस कंक्रीट के लिए केवल दो डीबी टेबल्स उत्पन्न करना चाहिए। मैं वास्तव में इस ऑब्जेक्ट कॉन्टेक्स्ट में एक असंगत राज्य त्रुटि में भाग गया था, और एकमात्र तरीका जिसे मैं इसे ठीक करने में सक्षम था, वह आईडी के बजाय बेसइन्टिटी प्रकार गइड में आईडी फ़ील्ड बनाना है (जो बदतर लगता है)। – blgrnboy

उत्तर

2

बस यह सब आसान बनाने के लिए, मैंने स्रोत खोलने के लिए TablePerConcrete को मजबूर करने के लिए आवश्यक कोड को स्थानांतरित कर दिया है।इसका उद्देश्य विशेष रूप से फ्लुएंट इंटरफ़ेस में उपलब्ध सुविधाओं को अनुमति देना है (जहां आपको विशेषता-आधारित सुविधाओं पर माइग्रेट करने के लिए अपने डीबी क्लास 'ऑनमोडेल क्रिएटिंग विधि) में बहुत अधिक कोड स्कैटर करना होगा। क्या एफई अपने माता पिता के वर्ग/उपवर्ग रिश्ते से अनुमान लगाने के लिए तय कर सकते हैं की परवाह किए बिना टीपीसी जबरदस्ती

[TablePerConcrete] 
public class MySubclassTable : MyParentClassEntity 

:

यह आप इस तरह काम करने की अनुमति देता है।

यहां एक दिलचस्प चुनौती यह है कि कभी-कभी ईएफ एक विरासत आईडी संपत्ति को खराब कर देगा, इसे डेटाबेस द्वारा उत्पन्न होने के बजाय स्पष्ट मूल्य से भरने के लिए सेट किया जाएगा। आप यह सुनिश्चित कर सकते हैं कि यह पैरेंट क्लास इंटरफ़ेस IId (जो केवल कहता है: इसमें एक आईडी प्रॉपर्टी है) को लागू करके ऐसा नहीं किया जाता है, फिर [ForcePKId] के साथ सबक्लास को चिह्नित किया जाता है।

public class MyParentClassEntity : IId 
{ 
    public int Id { get; set; } 
    . . . 

[TablePerConcrete] 
[ForcePKId] 
public class MySubclassTable : MyParentClassEntity 
{ 
    // No need for PK/Id property here, it was inherited and will work as 
    // you intended. 

कोड है कि आप के लिए यह सब संभालती बंद किकिंग बहुत सरल है - बस अपनी Db वर्ग के लिए एक जोड़े को पंक्तियां जोड़ें:

public class Db : DbContext 
{ 
    . . . 
    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     var modelsProject = Assembly.GetExecutingAssembly(); 
     B9DbExtender.New().Extend(modelBuilder, modelsProject); 

आप इसे 2 तरीकों में से एक का उपयोग कर सकते हैं:

  1. सभी प्रासंगिक वर्गों के साथ एक भी सार के माध्यम से एक एकल फाइल में कॉपी-पेस्ट किया था, यहाँ: https://gist.github.com/b9chris/8efd30687d554d1ceeb3fee359c179f9

  2. लाइब्रेरी के माध्यम से, हमारे ब्रास 9। डेटा, जिसे हम ओपन सोर्स जारी कर रहे हैं। इसमें डेटा माइग्रेशन जैसे कई अन्य ईएफ 6 उपकरण हैं। यह भी अधिक का आयोजन किया है, अलग-अलग फ़ाइलों में विभाजित कर के रूप में आप सामान्य रूप से उम्मीद थी वर्गों के साथ: https://github.com/b9chris/Brass9.Data

+1

लिंक्ड कोड गुम है "रिफ्लेक्शनहेल्पर" –

+0

@ एडमग्रीन फिक्स्ड!उसके लिए माफ़ करना। –

1

मैं मानचित्रण कक्षाएं, लेकिन कभी-मन का उपयोग करें। मैं इसे इस तरह हल करता हूं:

public class PersonMap : EntityTypeConfiguration<Person> 
{ 
    public PersonMap() 
    { 
     Map(m => { m.ToTable("Person"); m.MapInheritedProperties(); }); 

     HasKey(p => p.Id); 
     Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 
    } 

} 

याद रखें - बेस क्लास सार होना चाहिए।

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