9

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

मेरे उद्देश्यों के लिए, मुझे कोई परवाह नहीं है कि माइग्रेशन में एक्सटेंशन प्रदाता अज्ञेयवादी हो (एसक्यूएल मैं इन-लाइनिंग में नहीं हूं)। हालांकि, मुझे वास्तव में ऐसी चीजों को जोड़ने के लिए माइग्रेशन ढांचे में एक अच्छा सीम या विस्तार बिंदु नहीं मिल रहा है।

एक ठोस उदाहरण देने के लिए, मान लीजिए कि मैं एमएस-एसक्यूएल प्रतिकृति के लिए एक रोउगुइड कॉलम निर्दिष्ट करना चाहता हूं। हर घटना अतिरेक में से कुछ से छुटकारा पाने के की

Sql(
    string.Format(
     "Alter Table {0} Alter Column {1} Add ROWGUIDCOL", 
     table, 
     column)); 

तो मैं स्थिर तरीकों लिखना रूप ले लेता है

Sql(MigrationHelper.SetRowGuid(table, column); 

-या-

MigrationHelper.SetRowGuid(Sql, table, column); //passing the Sql method 

संभवतः उन विस्तार के दोनों कर सकता है डीबी माइग्रेशन पर विधियां, और this. तक उन्हें एक्सेस करें लेकिन फिर भी यह जगह से बाहर दिखता है:

CreateTable(
    "dbo.CustomerDirectory", 
    c => new 
     { 
      Uid = c.Int(nullable: false), 
      CustomerUid = c.Int(nullable: false), 
      Description = c.String(nullable: false, maxLength: 50, unicode: false), 
      RowGuid = c.Guid(nullable: false), 
     }) 
    .PrimaryKey(t => t.Uid) 
    .ForeignKey("dbo.Customer", t => t.CustomerUid); 

this.SetRowGuid(Sql, "dbo.CustomerDirectory", "RowGuid"); 
//Custom method here because of desired naming convention of Constraint 
this.SetDefaultConstraint(Sql, "dbo.CustomerDirectory", "''"): 

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

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

के कारण है कि मैं इस स्थिति में हूं जैसे कुछ औचित्य:

मैं क्या आम रिवाज उपयोग करने का एक आम समाधान तरह लग रहा था समाधान जिम्मेदार बताते हैं कुछ कारणों से गैर मानचित्रण डेटाबेस इंगित करने के लिए पसंद नहीं आया है, लेकिन सबसे ज्यादा क्योंकि वे अतिरिक्त रखरखाव का अर्थ माइग्रेशन द्वारा स्वचालित रूप से नहीं उठाए जाते हैं। मॉडल-पहले समाधान बाहर थे क्योंकि वे डेटाबेस पर पूर्ण नियंत्रण नहीं देते हैं। डाटाबेस-पहले नियंत्रण की वजह से आकर्षक था; हालांकि, इसमें बॉक्स ऑफ चेंज मैनेजमेंट कार्यक्षमता कोड-फर्स्ट माइग्रेशन प्रदान नहीं करता है। इस प्रकार, कोड-फर्स्ट माइग्रेशन विजेता प्रतीत होता था क्योंकि [कोड-प्रथम] मॉडल-संचालित परिवर्तन स्वचालित होते हैं और इसका मतलब है कि बनाए रखने के लिए केवल एक ही चीज़ होगी।

+0

+1 EFCF केवल इकाई की रूपरेखा दृष्टिकोण है कि वास्तव में परिवर्तन पर नियंत्रण की सुविधा के रूप में प्रकाश डाला के लिए। '[शुद्ध]' का उपयोग करने के लिए – bwerks

उत्तर

5

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

CreateTable(
    "dbo.CustomerDirectory", 
    c => new 
     { 
      Uid = c.Int(nullable: false), 
      CustomerUid = c.Int(nullable: false), 
      Description = c.String(nullable: false, maxLength: 50, unicode: false), 
      RowGuid = c.Guid(nullable: false), 
     }) 
    .PrimaryKey(t => t.Uid) 
    .ForeignKey("dbo.Customer", t => t.CustomerUid) 
     //SqlValue is a custom static helper class 
    .DefaultConstraint(t => t.Description, SqlValue.EmptyString) 
     //This is a convention in the project 
     //Equivalent to 
     // .DefaultConstraint(t => t.RowGuid, SqlValue.EmptyString) 
     // .RowGuid(t => t.RowGuid) 
    .StandardRowGuid() 
     //For one-offs 
    .Sql(tableName => string.Format("ALTER TABLE {0} ...", tableName"); 

मुझे पसंद नहीं है:

यह मेरे जैसे बयान लिखने की अनुमति देता

  • तथ्य यह है कि मैं निजी सदस्यों को दर्शाती रहा हूँ, और सामान्य रूप से इस तरह के एक समाधान का उपयोग नहीं होगा
  • कि लैम्बडा कॉलम का चयन करने के लिए गलत कॉलम नाम वापस कर सकता है यदि कॉलम परिभाषा के "नाम" वैकल्पिक पैरामीटर का उपयोग किया गया था।

मैं केवल यहां उसका उपयोग करना क्योंकि पर विचार कर रहा हूँ:

  • हम एफई विधानसभा जहाज तो हम इस्तेमाल किया इन सदस्यों होगा एक यकीन है कि कर रहे हैं।
  • एक जोड़े इकाई परीक्षण हमें बताएंगे कि कोई नया संस्करण इन्हें तोड़ देगा या नहीं।
  • यह माइग्रेशन के लिए अलग है।
  • हमारे पास ऐसी सभी जानकारी है जो हम प्राप्त करने के लिए प्रतिबिंबित कर रहे हैं, इसलिए यदि कोई नया संस्करण इसे तोड़ता है, तो हम इस कार्यक्षमता को प्रतिस्थापित करने के लिए एक हैक डाल सकते हैं।
internal static class TableBuilderExtentions 
{ 
    internal static TableBuilder<TColumns> Sql<TColumns>(
     this TableBuilder<TColumns> tableBuilder, 
     Func<string, string> sql, 
     bool suppressTransaction = false, 
     object anonymousArguments = null) 
    { 
     string sqlStatement = sql(tableBuilder.GetTableName()); 

     DbMigration dbMigration = tableBuilder.GetDbMigration(); 
     Action<string, bool, object> executeSql = dbMigration.GetSqlMethod(); 

     executeSql(sqlStatement, suppressTransaction, anonymousArguments); 

     return tableBuilder; 
    } 

    [Pure] 
    private static DbMigration GetDbMigration<TColumns>(this TableBuilder<TColumns> tableBuilder) 
    { 
     var field = tableBuilder.GetType().GetField(
      "_migration", BindingFlags.NonPublic | BindingFlags.Instance); 
     return (DbMigration)field.GetValue(tableBuilder); 
    } 

    /// <summary> 
    /// Caution: This implementation only works on single properties. 
    /// Also, coder may have specified the 'name' parameter which would make this invalid. 
    /// </summary> 
    private static string GetPropertyName<TColumns>(Expression<Func<TColumns, object>> someObject) 
    { 
     MemberExpression e = (MemberExpression)someObject.Body; 

     return e.Member.Name; 
    } 

    [Pure] 
    private static Action<string, bool, object> GetSqlMethod(this DbMigration migration) 
    { 
     MethodInfo methodInfo = typeof(DbMigration).GetMethod(
      "Sql", BindingFlags.NonPublic | BindingFlags.Instance); 
     return (s, b, arg3) => methodInfo.Invoke(migration, new[] { s, b, arg3 }); 
    } 

    [Pure] 
    private static string GetTableName<TColumns>(this TableBuilder<TColumns> tableBuilder) 
    { 
     var field = tableBuilder.GetType().GetField(
      "_createTableOperation", BindingFlags.NonPublic | BindingFlags.Instance); 

     var createTableOperation = (CreateTableOperation)field.GetValue(tableBuilder); 
     return createTableOperation.Name; 
    } 
} 
+2

+1 – nicodemus13

0

एक सामान्य समाधान नहीं है, लेकिन आप एक सार/इंटरफ़ेस वर्ग से प्राप्त कर सकते हैं। यह देखते हुए कि कुछ कोड परिवर्तनों की आवश्यकता होगी लेकिन यह उचित रूप से साफ है।

मैंने सभी तालिकाओं के लिए अपने ऑडिट कॉलम (अपडेटेडबी, अपडेटडेट इत्यादि) को परिभाषित करने के लिए इस पैटर्न का उपयोग किया है।

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