2017-03-15 5 views
5

मेरी तालिका में से किसी एक के लिए एक नया एक-एक संबंध जोड़ने के बाद मैं यह नहीं समझ सकता कि मेरे डेटाबेस में मौजूदा पंक्तियों के लिए डिफ़ॉल्ट डेटा कैसे जोड़ना है।ईएफ कोर में एक-से-एक संबंध जोड़ते समय डेटा माइग्रेट करना?

मेरे डेटाबेस मूल रूप से इस तरह देखा अपग्रेड से पहले:

-- Team -- 
    Name: TEXT 

-- History -- 
    Id: INT 

... जहां इतिहास है विदेशी कुंजी है अन्य असंबंधित टेबल से यह ओर इशारा किया।

मेरी उन्नयन में मैं मूल रूप से एक भी इतिहास के लिए एक टीम चाहते हैं तो अपने नए db लगता है:

-- Team -- 
    Name: TEXT 
    HistoryId: INT 

-- History -- 
    Id: INT 

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

मैंने अपने माइग्रेशन में अप-विधि में मैन्युअल रूप से प्रविष्टियों को जोड़ने का प्रयास किया, लेकिन चूंकि मेरे मॉडल मौजूदा स्कीमा से मेल नहीं खाते हैं, यह विफल हो जाता है।

protected override void Up(MigrationBuilder migrationBuilder) 
{ 
    migrationBuilder.AddColumn<int>(
     name: "HistoryId", 
     table: "Team", 
     nullable: false, 
     defaultValue: 0); 

    using (var db = new XMDBContext()) 
    { 
     foreach (var team in db.Team) 
      team.History = new XMHistory(); 
     db.SaveChanges(); 
    } 

    migrationBuilder.CreateIndex(
     name: "IX_Team_HistoryId", 
     table: "Team", 
     column: "HistoryId", 
     unique: true); 

    migrationBuilder.AddForeignKey(
     name: "FK_Team_History_HistoryId", 
     table: "Team", 
     column: "HistoryId", 
     principalTable: "History", 
     principalColumn: "Id", 
     onDelete: ReferentialAction.Cascade); 
} 

उत्तर

4

दुर्भाग्यवश वर्तमान में ईएफ कोर माइग्रेशन से बीजिंग डेटा का समर्थन नहीं करता है। इस मुद्दे को उनके भंडार में #629 - Seed Data के रूप में ट्रैक किया गया है।

वर्तमान में देखे जाने वाला एकमात्र समाधान MigrationBuilder.Sql विधि के माध्यम से पुराना अच्छा एसक्यूएल का उपयोग कर रहा है। दुर्भाग्य से डीबी प्रदाता सेवाओं तक कोई पहुंच नहीं है, इसलिए अगला SQL सर्वर पर लागू होता है (हालांकि मैंने केवल मानक SQL आदेशों का उपयोग करने का प्रयास किया है)।

चलो मूल मॉडल इस प्रकार थी:

public class Team 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class History 
{ 
    public int Id { get; set; } 
} 

FK जोड़ने के बाद Team से History के लिए यह हो जाता है:

public class Team 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int HistoryId { get; set; } 
    public History History { get; set; } 
} 

स्वचालित रूप से जेनरेट प्रवास है:

protected override void Up(MigrationBuilder migrationBuilder) 
{ 
    migrationBuilder.AddColumn<int>(
     name: "HistoryId", 
     table: "Team", 
     nullable: false, 
     defaultValue: 0); 

    migrationBuilder.CreateIndex(
     name: "IX_Team_HistoryId", 
     table: "Team", 
     column: "HistoryId"); 

    migrationBuilder.AddForeignKey(
     name: "FK_Team_History_HistoryId", 
     table: "Team", 
     column: "HistoryId", 
     principalTable: "History", 
     principalColumn: "Id", 
     onDelete: ReferentialAction.Cascade); 
} 

अब , CreateIndex कमांड से पहले हम मैन्युअल रूप से सम्मिलित करते हैं निम्नलिखित:

migrationBuilder.AddColumn<int>(
    name: "TeamId", 
    table: "History", 
    nullable: true); 

migrationBuilder.Sql(@"insert into History (TeamId) select Id from Team"); 

migrationBuilder.Sql(@"update Team set HistoryId = (select Id from History where TeamId = Team.Id)"); 

migrationBuilder.DropColumn(
    name: "TeamId", 
    table: "History"); 

विचार सरल है। हम History तालिका में एक अस्थायी व्यर्थ स्तम्भ TeamId बनाने के लिए, Team तालिका में इसी TeamId प्रत्येक रिकॉर्ड के लिए के साथ एक नया रिकॉर्ड सम्मिलित है, तो एक कुंजी के रूप में History मेज से TeamId स्तंभ का उपयोग Team तालिका में HistoryId स्तंभ को अद्यतन, और अंत में हटाना अस्थायी कॉलम

इस बिंदु पर डेटा परिवर्तन पूर्ण हो गया है और एफके बाधा उत्पन्न की जा सकती है।

अच्छे प्रथाओं से दूर, लेकिन कामकाज के रूप में उपयोग किया जा सकता है।

संपादित करें:Gert Arnold's comments के बाद, लग रहा है एसक्यूएल ब्लॉकों का उपयोग कर की तरह जाने के लिए सही रास्ता है। केवल एक चीज जो मुझे चिंतित करती है वह डेटाबेस अज्ञेयवादी और/या विशिष्ट एसक्यूएल कैसे लिखना है। बेशक समस्या मौजूद नहीं है यदि कोई एक विशिष्ट डेटाबेस प्रकार को लक्षित कर रहा है।वैसे भी, यदि विभिन्न डेटाबेस प्रकारों को संभालने की आवश्यकता है, तो कोई भी MigrationBuilder.ActiveProvider संपत्ति के आधार पर विशिष्ट if ब्लॉक के साथ संयुक्त सभी लक्षित डेटाबेस द्वारा समर्थित मानक SQL आदेशों का उपयोग कर सकता है।

+0

अच्छा इवान दिखता है! और मुझे लगता है कि यह जाने का एकमात्र तरीका है। यहां तक ​​कि यदि कोई बीज विधि थी तो इससे मदद नहीं मिली होगी क्योंकि यह * डेटाबेस अपग्रेड के दौरान * नहीं चलती है। इस परिदृश्य को हमेशा कुछ मध्यस्थ डेटाबेस स्थिति की आवश्यकता होती है क्योंकि आप अभी तक ऐसा कुछ नहीं करने के लिए एक आवश्यक एफके जोड़ नहीं सकते हैं। –

+0

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

+0

... तो एसक्यूएल तरीका हो सकता है, डीबी एग्नोस्टिक एसक्यूएल लिखने के लिए बस कुछ जानकारी/हेल्पर्स (जैसे 'माइक्रोन जेनरेशनहेल्पर '' माइग्रेशन स्क्लजेनरेटर 'में इस्तेमाल किया जाना चाहिए)। या सीधे 'माइग्रेशनस्कलबिल्डर' में हुक करने का एक तरीका। चूंकि हमारे पास वर्तमान में 'माइग्रेशनबिल्डर' एक्टिवप्रोवाइडर 'स्ट्रिंग है (जो निश्चित रूप से कुछ भी नहीं है :)। –

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