48

मैं एंटरिटी फ्रेमवर्क पावर टूल्स बीटा 2 के साथ विजुअल स्टूडियो के साथ एंटीटी फ्रेमवर्क 5 का उपयोग कर रहा हूं ताकि अभियंता मध्यम आकार के डेटाबेस (~ 100 टेबल) को रिवर्स किया जा सके।डेटाबेस को रिवर्स करते समय नेविगेशन प्रॉपर्टी नामों में सुधार करें

दुर्भाग्य से, नेविगेशन गुणों के अर्थपूर्ण नाम नहीं हैं।

CREATE TABLE Contacts (
    ContactID INT IDENTITY (1, 1) NOT NULL, 
    ... 
    CONSTRAINT PK_Contacts PRIMARY KEY CLUSTERED (ContactID ASC) 
} 

CREATE TABLE Projects (
    ProjectID INT IDENTITY (1, 1) NOT NULL, 
    TechnicalContactID INT NOT NULL, 
    SalesContactID INT NOT NULL, 
    ... 
    CONSTRAINT PK_Projects PRIMARY KEY CLUSTERED (ProjectID ASC), 
    CONSTRAINT FK_Projects_TechnicalContact FOREIGN KEY (TechnicalContactID) 
     REFERENCES Contacts (ContactID), 
    CONSTRAINT FK_Projects_SalesContact FOREIGN KEY (SalesContactID) 
     REFERENCES Contacts (ContactID), 
    ... 
} 

यह इस तरह की कक्षाओं उत्पन्न होगा: उदाहरण के लिए, अगर वहाँ दो तालिकाओं हैं

public class Contact 
{ 
    public Contact() 
    { 
      this.Projects = new List<Project>(); 
      this.Projects1 = new List<Project>(); 
    } 
    public int ContactID { get; set; } 
    // ... 
    public virtual ICollection<Project> Projects { get; set; } 
    public virtual ICollection<Project> Projects1 { get; set; } 
} 

public class Project 
{ 
    public Project() 
    { 

    } 
    public int ProjectID { get; set; } 
    public int TechnicalContactID { get; set; } 
    public int SalesContactID { get; set; } 
    // ... 
    public virtual Contact Contact { get; set; } 
    public virtual Contact Contact1 { get; set; } 
} 

मैं कई वेरिएंट है जो सभी इस से बेहतर होगा देखें:

  • उपयोग विदेशी कुंजी का नाम: उदाहरण के लिए, अंतिम अंडरस्कोर (FK_Projects_TechnicalContact ->TechnicalContact) के बाद सबकुछ। हालांकि यह शायद सबसे अधिक नियंत्रण वाला समाधान होगा, मौजूदा टेम्पलेट्स के साथ एकीकृत करना अधिक कठिन हो सकता है। उदाहरण TechnicalContactIDProjects (संग्रह) और: - (>TechnicalContactTechnicalContactID)
  • उपयोग संपत्ति नाम की संयोजन और मौजूदा समाधान पट्टी प्रत्यय ID बंद:
  • विदेशी कुंजी स्तंभ के लिए इसी संपत्ति नाम का प्रयोग करें TechnicalContactIDContact

सौभाग्य से, it is possible to modify the templates by including them in the project

संशोधनों को Entity.tt और Mapping.tt पर बनाना होगा। मुझे उन परिवर्तनों को करने के लिए इंटेलिजेंस और डीबग संभावनाओं की कमी के कारण यह मुश्किल लगता है।


श्रृंखलाबद्ध संपत्ति के नाम (तीसरी उपरोक्त सूची में) शायद लागू करने के लिए सबसे आसान उपाय है।

public class Contact 
{ 
    public Contact() 
    { 
      this.TechnicalContactIDProjects = new List<Project>(); 
      this.SalesContactIDProjects = new List<Project>(); 
    } 
    public int ContactID { get; set; } 
    // ... 
    public virtual ICollection<Project> TechnicalContactIDProjects { get; set; } 
    public virtual ICollection<Project> SalesContactIDProjects { get; set; } 
} 

public class Project 
{ 
    public Project() 
    { 

    } 
    public int ProjectID { get; set; } 
    public int TechnicalContactID { get; set; } 
    public int SalesContactID { get; set; } 
    // ... 
    public virtual Contact TechnicalContactIDContact { get; set; } 
    public virtual Contact SalesContactIDContact { get; set; } 
} 
+1

एफवाईआई, आप टी 4 संपादन को थोड़ा आसान बनाने के लिए मूर्त टी 4 संपादक डाउनलोड और उपयोग कर सकते हैं: http://t4-editor.tangible-engineering.com/T4- संपादक- विज़ुअल- टी 4-Editing.html। मुफ्त संस्करण सीमित है, लेकिन यह कुछ भी नहीं से बेहतर है :) – Spikeh

उत्तर

45
वहाँ

कुछ चीजें आप .tt फाइल के अंदर बदलने की जरूरत:

Entity.tt और Mapping.tt में नौवहन गुण के निर्माण के बदलने के लिए निम्न परिणाम प्राप्त करने के लिए। मैं आपके द्वारा सुझाए गए तीसरे समाधान का उपयोग करना चुनता हूं लेकिन इसे FK_CollectionName_RelationName जैसे प्रारूपित करने की आवश्यकता है। मैंने उन्हें '_' के साथ विभाजित किया और सरणी में अंतिम स्ट्रिंग का उपयोग किया। मैं संपत्ति नाम बनाने के लिए ToEndMember संपत्ति के साथ RelationName का उपयोग करता हूं। FK_Projects_TechnicalContact के परिणामस्वरूप

//Plularized because of EF. 
public virtual Contacts TechnicalContactContacts { get; set; } 

और आपकी परियोजनाएं इस तरह होंगी।

public virtual ICollection<Projects> SalesContactProjects { get; set; } 
public virtual ICollection<Projects> TechnicalContactProjects { get; set; } 

अब आप जो कोड पूछ सकते हैं। Ive ने T4 फ़ाइल में CodeStringGenerator कक्षा में 2 फ़ंक्शंस जोड़े। एक जो संपत्ति बनाता है नाम नेविगेशन प्रॉपर्टी प्राप्त कर रहा है। और दूसरा एक नेविगेशन प्रॉपर्टी प्राप्त करने वाली संपत्ति के लिए कोड उत्पन्न करता है और संपत्ति के लिए नाम प्राप्त करता है।

//CodeStringGenerator class 
public string GetPropertyNameForNavigationProperty(NavigationProperty navigationProperty) 
{ 
    var ForeignKeyName = navigationProperty.RelationshipType.Name.Split('_'); 
    var propertyName = ForeignKeyName[ForeignKeyName.Length-1] + navigationProperty.ToEndMember.Name; 
    return propertyName; 
} 

public string NavigationProperty(NavigationProperty navigationProperty, string name) 
{ 
    var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType()); 
    return string.Format(
     CultureInfo.InvariantCulture, 
     "{0} {1} {2} {{ {3}get; {4}set; }}", 
     AccessibilityAndVirtual(Accessibility.ForProperty(navigationProperty)), 
     navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType, 
     name, 
     _code.SpaceAfter(Accessibility.ForGetter(navigationProperty)), 
     _code.SpaceAfter(Accessibility.ForSetter(navigationProperty))); 
} 

यदि आप कक्षा में उपरोक्त कोड रखते हैं तो आपको अभी भी 2 भागों को बदलने की आवश्यकता है। आपको उस स्थान को ढूंढना होगा जहां कन्स्ट्रक्टर भाग और नेविगेशन प्रॉपर्टी भाग इकाई का निर्माण किया जा रहा है। कन्स्ट्रक्टर भाग में (लाइन 60 के आसपास) आपको विधि GetPropertyNameForNavigationProperty पर कॉल करके मौजूदा कोड को प्रतिस्थापित करने और इसे बचने की विधि में पास करने की आवश्यकता है।

 var propName = codeStringGenerator.GetPropertyNameForNavigationProperty(navigationProperty); 
#> 
     this.<#=code.Escape(propName)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>(); 
<# 

और नेविगेशन प्रॉपर्टीज भाग (लगभग 100 पंक्ति) में आपको कोड को निम्नलिखित के साथ प्रतिस्थापित करने की भी आवश्यकता है।

var propName = codeStringGenerator.GetPropertyNameForNavigationProperty(navigationProperty); 
#> 
    <#=codeStringGenerator.NavigationProperty(navigationProperty, propName)#> 
<# 

मुझे आशा है कि इस मदद करता है और आप हमेशा GetPropertyNameForNavigationProperty समारोह डिबग और संपत्ति के नामकरण के साथ एक छोटे से खेल सकते हैं।

+1

कौन सी टी 4 फ़ाइल में 'कोडस्ट्रिंग जेनरेटर' कक्षा है? – marapet

+1

EntityFramework में model.tt 5. यह लगभग 260 के आसपास छिपा हुआ है। यहां एक स्क्रीनशॉट है जो http://imgur.com/f6PNq –

+0

मदद कर सकता है यह फ़ाइल कहां स्थित है? क्या आपने "एंटिटी फ्रेमवर्क पावर टूल्स बीटा 2" की "रिवर्स इंजीनियर कोड फर्स्ट" कार्यक्षमता का उपयोग किया था? – marapet

3

इस प्रश्न/उत्तर को बहुत उपयोगी पाया। हालांकि, मैं रिकको के जवाब जितना ज्यादा नहीं करना चाहता था। मुझे केवल नेविगेशन प्रॉपर्टी में शामिल कॉलम नाम खोजने की आवश्यकता थी और यह नहीं देख रहा था कि किसी भी नमूने में इसे कैसे प्राप्त किया जाए (कम से कम एडीएमएक्स के बिना खींचने के लिए)।

<# 
    var association = (AssociationType)navProperty.RelationshipType; 
#> // <#= association.ReferentialConstraints.Single().ToProperties.Single().Name #> 
+0

अगर यह संयुक्त है तो उत्तर के रूप में चिह्नित किया गया है। –

4

बिल्डिंग BikeMrown के जवाब पर, हम RelationshipName उपयोग करने वाली प्रॉपर्टी कि MSSQL में सेट किया गया है करने के लिए Intellisense जोड़ सकते हैं: अपने वी.एस. परियोजना में model.tt

MSSQL relationships

संपादित करें, और यह बदलने के लिए:

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 
<# 
      } 
#> 
    <#=codeStringGenerator.NavigationProperty(navigationProperty)#> 
<# 
     } 
    } 
इस के लिए

:

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 
<# 
      } 
#> 
    /// <summary> 
    /// RelationshipName: <#=code.Escape(navigationProperty.RelationshipType.Name)#> 
    /// </summary> 
    <#=codeStringGenerator.NavigationProperty(navigationProperty)#> 
<# 
     } 
    } 

अब जब आप एक संपत्ति नाम लिखना शुरू करें, तो आप एक टूलटिप इस तरह मिलती है: Intellisense tooltip

यह शायद ध्यान देने योग्य है यदि आप अपने डीबी मॉडल बदलने के लिए, संपत्तियों खुद अलग डीबी क्षेत्रों पर इशारा करते हुए पा सकते हैं कि है, क्योंकि ईएफ ने अपने संबंधित डीबी क्षेत्र के नाम की वर्णमाला प्राथमिकता के आधार पर नेविगेशन संपत्ति नाम उत्पन्न किए हैं!

0

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

public virtual Need UnitNeed { get; set;} 
public virtual ShiftEntered UnitShiftEntered {get; set;}` 

तो मैं .tt फाइल करने के लिए प्रस्तावित अतिरिक्त में खोदे गए और उन्हें थोड़ा संशोधित डुप्लिकेट प्रकार नामकरण और स्वच्छ चीजों को थोड़ा दूर करने के लिए। मुझे लगता है कि वहाँ कोई और होना चाहिए जो एक ही चीज़ चाहते हैं, इसलिए मुझे लगा कि मैं अपना संकल्प यहां पोस्ट करूंगा।

यहाँ public class CodeStringGenerator

public string GetPropertyNameForNavigationProperty(NavigationProperty navigationProperty, string entityname = "") 
{ 
    var ForeignKeyName = navigationProperty.RelationshipType.Name.Split('_'); 
    var propertyName = ""; 

    if (ForeignKeyName[ForeignKeyName.Length-1] != entityname){ 
     var prepender = (ForeignKeyName[ForeignKeyName.Length-1].EndsWith(entityname)) ? ReplaceLastOccurrence(ForeignKeyName[ForeignKeyName.Length-1], entityname, "") : ForeignKeyName[ForeignKeyName.Length-1]; 
     propertyName = prepender + navigationProperty.ToEndMember.Name; 
    } 
    else { 
     propertyName = navigationProperty.ToEndMember.Name; 
    } 

    return propertyName; 
} 

public string NavigationProperty(NavigationProperty navigationProperty, string name) 
{ 
    var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType()); 

    var truname = name; 

    if(navigationProperty.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many){ 
     if(name.Split(endType.ToArray<char>()).Length > 1){ 
      truname = ReplaceLastOccurrence(name, endType, ""); 
     } 
    } 

    return string.Format(
     CultureInfo.InvariantCulture, 
     "{0} {1} {2} {{ {3}get; {4}set; }}", 
     AccessibilityAndVirtual(Accessibility.ForProperty(navigationProperty)), 
     navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType, 
     truname, 
     _code.SpaceAfter(Accessibility.ForGetter(navigationProperty)), 
     _code.SpaceAfter(Accessibility.ForSetter(navigationProperty))); 
} 

public static string ReplaceLastOccurrence(string Source, string Find, string Replace) 
{ 
     int place = Source.LastIndexOf(Find); 

     if(place == -1) 
      return Source; 

     string result = Source.Remove(place, Find.Length).Insert(place, Replace); 
     return result; 
} 

भीतर अद्यतन करने के लिए कोड है और यहां मॉडल पीढ़ी के भीतर अपडेट करने के लिए कोड है, इस बात का

अद्यतन दोनों घटनाओं: इस

को

var propName = codeStringGenerator.GetPropertyNameForNavigationProperty(navigationProperty) 

var propName = codeStringGenerator.GetPropertyNameForNavigationProperty(navigationProperty, entity.Name); 
+0

मैंने अभी भी इसे जिथब में जोड़ा है (अस्वीकरण, मैं गीथब में अच्छी तरह से नहीं जानता) https://github.com/DylanTheDev/EF-NavPropFix/blob/master/EFModel.tt –

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