प्रस्तुत फ़ॉर डिज़ाइन कुंजी बाधा चक्र या एकाधिक कैस्केड पथ का कारण बन सकती है - क्यों?


295

मैं इसके साथ थोड़ी देर के लिए कुश्ती कर रहा हूं और यह पता नहीं लगा सकता कि क्या हो रहा है। मेरे पास एक कार्ड इकाई है जिसमें साइड्स (आमतौर पर 2) हैं - और दोनों कार्ड्स और साइड्स में एक स्टेज है। मैं EF Codefirst माइग्रेशन का उपयोग कर रहा हूं और इस त्रुटि के साथ माइग्रेशन विफल हो रहे हैं:

मंच पर 'फ़ॉइड_डॉ.साइड_डेबो.साइड्स_कार्ड्स'कार्ड_ड' 'फ़ॉइंड डिज़ाइन की कमी के कारण साइकल या कई कैस्केड पथ हो सकते हैं। DELETE NO ACTION या UPDATE NO ACTION को निर्दिष्ट करें, या अन्य FOREIGN कुंजी बाधाओं को संशोधित करें।

यहाँ मेरी कार्ड इकाई है:

public class Card
{
    public Card()
    {
        Sides = new Collection<Side>();
        Stage = Stage.ONE;
    }

    [Key]
    [Required]
    public virtual int CardId { get; set; }

    [Required]
    public virtual Stage Stage { get; set; }

    [Required]
    [ForeignKey("CardId")]
    public virtual ICollection<Side> Sides { get; set; }
}

यहाँ मेरी साइड इकाई है:

public class Side
{
    public Side()
    {
        Stage = Stage.ONE;
    }

    [Key]
    [Required]     
    public virtual int SideId { get; set; } 

    [Required]
    public virtual Stage Stage { get; set; }

    [Required]
    public int CardId { get; set; }

    [ForeignKey("CardId")]
    public virtual Card Card { get; set; }

}

और यहाँ मेरी स्टेज इकाई है:

public class Stage
{
    // Zero
    public static readonly Stage ONE = new Stage(new TimeSpan(0, 0, 0), "ONE");
    // Ten seconds
    public static readonly Stage TWO = new Stage(new TimeSpan(0, 0, 10), "TWO");

    public static IEnumerable<Stage> Values
    {
        get
        {
            yield return ONE;
            yield return TWO;
        }

    }

    public int StageId { get; set; }
    private readonly TimeSpan span;
    public string Title { get; set; }

    Stage(TimeSpan span, string title)
    {
        this.span = span;
        this.Title = title;
    }

    public TimeSpan Span { get { return span; } }
}

यह अजीब है कि अगर मैं निम्नलिखित को अपने स्टेज वर्ग में शामिल करूं:

    public int? SideId { get; set; }
    [ForeignKey("SideId")]
    public virtual Side Side { get; set; }

प्रवास सफलतापूर्वक चलता है। यदि मैं SSMS खोलता हूं और तालिकाओं को देखता हूं, तो मैं देख सकता हूं कि (जैसा कि अपेक्षित / इच्छित) Stage_StageIdमें जोड़ा गया है Cards, हालांकि Sidesइसमें कोई संदर्भ Stageनहीं है (अपेक्षित नहीं)।

अगर मैं जोड़ूं तो

    [Required]
    [ForeignKey("StageId")]
    public virtual Stage Stage { get; set; }
    public int StageId { get; set; }

मेरी साइड क्लास के लिए, मुझे StageIdअपनी Sideटेबल में कॉलम जोड़ा गया है ।

यह काम कर रहा है, लेकिन अब मेरे आवेदन में, किसी भी संदर्भ Stageमें ए शामिल है SideId, जो कुछ मामलों में पूरी तरह अप्रासंगिक है। यदि संभव हो तो संदर्भ संपत्तियों के साथ मंच वर्ग को प्रदूषित किए बिना मैं केवल अपनी Cardऔर Sideसंस्थाओं Stageको उपरोक्त चरण वर्ग के आधार पर एक संपत्ति देना चाहूंगा ... क्या मैं गलत कर रहा हूं?


7
संदर्भों में अशक्त मानों की अनुमति देकर कैस्केडिंग को अक्षम करें ... इसलिए Sideकक्षा में अशक्त पूर्णांक जोड़ें और [Required]विशेषता => public int? CardId { get; set; }
हटाएं

2
एफई कोर में, आप के साथ हटाना झरना अक्षम करना चाहिए DeleteBehavior.Restrictया DeleteBehavior.SetNull
सीना लोटी 14

जवाबों:


371

क्योंकि Stageहै की आवश्यकता है, सभी एक-से-कई रिश्तों को जहां Stageशामिल है हटाने डिफ़ॉल्ट रूप से सक्षम व्यापक होगा। इसका मतलब है, यदि आप किसी Stageइकाई को हटाते हैं

  • हटाने के लिए सीधे कैस्केड किया जाएगा Side
  • हटाने सीधे करने के लिए झरना Cardऔर क्योंकि Cardऔर Sideएक हटाने व्यापक डिफ़ॉल्ट इसे फिर से फिर से झरना रूप से सक्षम के साथ एक-से-कई संबंध की जरुरत Cardके लिएSide

तो, आप से दो व्यापक हटाने पथ है Stageकरने के लिए Sideजो अपवाद का कारण बनता है -।

आपको या तो Stageकम से कम एक संस्था में वैकल्पिक बनाना चाहिए (यानी [Required]गुणों से विशेषता हटाएं Stage) या धाराप्रवाह एपीआई को धाराप्रवाह एपीआई के साथ अक्षम करें (डेटा एनोटेशन के साथ संभव नहीं):

modelBuilder.Entity<Card>()
    .HasRequired(c => c.Stage)
    .WithMany()
    .WillCascadeOnDelete(false);

modelBuilder.Entity<Side>()
    .HasRequired(s => s.Stage)
    .WithMany()
    .WillCascadeOnDelete(false);

2
धन्यवाद शालूमा। यदि मैं धाराप्रवाह एपीआई का उपयोग करता हूं जैसा कि आपने ऊपर दिखाया है, तो क्या अन्य क्षेत्र अपने कैस्केड को हटाएंगे व्यवहार को बनाए रखेंगे? उदाहरण के लिए, कार्ड्स डिलीट होने पर मुझे अभी भी साइड्स डिलीट करने की जरूरत है।
SB2055

1
@ SB2055: हाँ, यह केवल रिश्तों को प्रभावित करेगा Stage। अन्य रिश्ते अपरिवर्तित रहते हैं।
सलुमा

2
क्या विच गुण को जानने का कोई तरीका है जिससे त्रुटि हो रही है? मुझे वही समस्या हो रही है, और अपनी कक्षाओं को देखकर मैं नहीं देख सकता कि साइकिल कहाँ है
रोड्रिगो जुआरेज़

4
क्या यह उनके कार्यान्वयन में एक सीमा है? मुझे Stageहटाने के लिए ठीक करने के लिए Sideदोनों के लिए सीधे नीचे और के माध्यम से लगता है एकCard
आआआआआआआआआआआआआआआआआआआआआआआआआआआआआआ में

1
मान लीजिए कि हमने CascadeOnDelete को असत्य पर सेट किया। फिर हमने एक स्टेज रिकॉर्ड निकाला जो कार्ड के किसी एक रिकॉर्ड से संबंधित है। क्या होता है Card.Stage (FK)? क्या यह वही रहता है? या यह अशक्त करने के लिए सेट है?
नौ

61

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

[ForeignKey("StageId")]
public virtual Stage Stage { get; set; }
public int? StageId { get; set; }

5
मैंने [आवश्यक] टैग को हटा दिया था, लेकिन महत्वपूर्ण बात यह थी कि इसे अशक्त होने के int?बजाय उपयोग करना था int
वीएसबी

1
मैंने कैस्केड डिलीट को बंद करने के कई अलग-अलग तरीकों की कोशिश की और कुछ भी काम नहीं किया - यह तय हो गया!
20.05 पर ambog36

5
यदि आप स्टेज को शून्य पर सेट करने की अनुमति नहीं देना चाहते हैं तो आपको ऐसा नहीं करना चाहिए (मूल प्रश्न में स्टेज एक आवश्यक फ़ील्ड था)।
cfwall

35

कोई भी सोचता है कि ईएफ कोर में यह कैसे करना है:

      protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
                {
                    relationship.DeleteBehavior = DeleteBehavior.Restrict;
                }
           ..... rest of the code.....

3
यह सभी रिश्तों पर कैस्केड हटाने को बंद कर देगा। कैस्केड डिलीट कुछ उपयोग मामलों के लिए एक वांछित विशेषता हो सकती है।
ब्लेज़

15
वैकल्पिक रूप से,builder.HasOne(x => x.Stage).WithMany().HasForeignKey(x => x.StageId).OnDelete(DeleteBehavior.Restrict);
बिस्कुट 11

@ बिस्कुट या तो विस्तार के तरीके समय के साथ बदल गए या आप builder _ .Entity<TEntity>() _पहले HasOne() कहे गए भूल गए ...
ViRuSTriNiTy

1
@ViRuSTriNiTy, मेरी स्निपेट 2 साल पुरानी है। लेकिन, मुझे लगता है कि आप सही हैं - आजकल यह तब होगा जब आप इसे लागू करने का विकल्प चुनेंगे IEntityTypeConfiguration<T>। मुझे builder.Entity<T>उन दिनों विधि को याद नहीं है , लेकिन मैं गलत हो सकता है। फिर भी, वे दोनों काम करेंगे :)
बिस्कुट

21

जब मैं एक EF7 मॉडल से EF6 संस्करण में माइग्रेट कर रहा था, तो मुझे बहुत सी संस्थाओं के लिए यह त्रुटि मिल रही थी। मैं एक समय में प्रत्येक इकाई के माध्यम से जाना नहीं चाहता था, इसलिए मैंने उपयोग किया:

builder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
builder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

2
इसे उस क्लास (तों) में जोड़ा जाना चाहिए जो OnModelCreating मेथड में DbContext उदाहरण से प्राप्त होता है। बिल्डर DbModelBuilder प्रकार का है
कोडिंगयूरलाइफ

यह मेरे लिए काम किया; .NET 4.7, EF 6. एक स्टंबलिंग ब्लॉक मुझे त्रुटि मिली थी, इसलिए जब मैंने माइग्रेशन स्क्रिप्ट को इन कन्वेंशनों के साथ हटा दिया, तब उसने मदद करने के लिए APPEAR नहीं किया। "-Force" के साथ "ऐड-माइग्रेशन" को चलाने से यह सब साफ़ हो गया, और ऊपर इन सम्मेलनों सहित इसे फिर से बनाया गया। समस्या हल ...
जेम्स जॉयस

वे .net कोर में मौजूद नहीं हैं, वहाँ कोई समकक्ष?
jjxtra


20

आप cascadeDelete को गलत या सही (अपने माइग्रेशन अप () विधि में) सेट कर सकते हैं। अपनी आवश्यकता पर निर्भर करता है।

AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false);

2
@ मुसाखिर आपको जवाब देने के लिए धन्यवाद। आपका रास्ता बहुत ही सुरुचिपूर्ण और अधिक है - यह अधिक सटीक और सीधे उस समस्या पर लक्षित है जिसका मैं सामना कर रहा हूँ!
नोज़ीम तुरकुलोव

बस यह मत भूलो कि UPविधि को बाहरी संचालन द्वारा संशोधित किया जा सकता है।
दमनक

8

.NET Core में मैंने OnDelete विकल्प को ReferencialAction.NoAction में बदल दिया

         constraints: table =>
            {
                table.PrimaryKey("PK_Schedule", x => x.Id);
                table.ForeignKey(
                    name: "FK_Schedule_Teams_HomeId",
                    column: x => x.HomeId,
                    principalTable: "Teams",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.NoAction);
                table.ForeignKey(
                    name: "FK_Schedule_Teams_VisitorId",
                    column: x => x.VisitorId,
                    principalTable: "Teams",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.NoAction);
            });

7

मेरे पास यह मुद्दा भी था, मैंने एक समान धागे से इस जवाब के साथ इसे तुरंत हल किया

मेरे मामले में, मैं कुंजी हटाने पर निर्भर रिकॉर्ड को हटाना नहीं चाहता था। यदि आपकी स्थिति में यह स्थिति है तो बस माइग्रेशन में बूलियन मान को गलत में बदलें:

AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false);

संभावना है, यदि आप ऐसे रिश्ते बना रहे हैं जो इस संकलक त्रुटि को फेंक देते हैं, लेकिन कैस्केड डिलीट को बनाए रखना चाहते हैं; आप अपने रिश्तों के साथ एक मुद्दा है।


6

मैंने यह तय किया। जब आप माइग्रेशन जोड़ते हैं, तो ऊपर () विधि में इस तरह एक लाइन होगी:

.ForeignKey("dbo.Members", t => t.MemberId, cascadeDelete:True)

यदि आप अंत में cascadeDelete को हटा देते हैं तो यह काम करेगा।


5

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

इस विधि को संदर्भ डेटाबेस वर्ग में जोड़ें:

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}

1

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


1

में नेट कोर मैं सभी ऊपरी जवाब के साथ खेला - लेकिन किसी भी सफलता नहीं मिली। मैंने DB संरचना में बहुत बदलाव किए और हर बार नए प्रवासन का प्रयास कियाupdate-database , लेकिन वही त्रुटि मिली।

फिर मैं करने लगा remove-migration एक-एक करके जब तक कि पैकेज मैनेजर कंसोल ने मुझे अपवाद नहीं दिया:

माइग्रेशन '20170827183131 _ ***' पहले ही डेटाबेस पर लागू हो चुका है

उसके बाद, मैंने नया माइग्रेशन ( add-migration) और जोड़ाupdate-database सफलतापूर्वक

तो मेरा सुझाव होगा: अपने सभी अस्थायी पलायन को हटा दें, जब तक कि आपका वर्तमान डीबी राज्य न हो।


1

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

इसके बजाय मुझे इस कमांड को चलाना था जब वर्तमान db संरचना वर्तमान एक है:

Add-Migration Initial -IgnoreChanges

Db संरचना में एक वास्तविक समस्या होने की संभावना है लेकिन एक बार में दुनिया को एक कदम बचाएं ...


1

इसका सरल तरीका यह है कि अपनी माइग्रेशन फ़ाइल (cascadeDelete: true)को (cascadeDelete: false)तब संपादित करें जब आपके पैकेज मैनेजर कंसोल में अपडेट-डेटाबेस कमांड को असाइन करें। यदि यह आपके पिछले माइग्रेशन के साथ समस्या है तो सब ठीक है। अन्यथा अपने पहले के माइग्रेशन इतिहास की जांच करें, उन चीजों को कॉपी करें, अपने अंतिम माइग्रेशन फ़ाइल में पेस्ट करें, इसके बाद उसी कार्य को करें। यह पूरी तरह से मेरे लिए काम करता है।


1
public partial class recommended_books : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.RecommendedBook",
            c => new
                {
                    RecommendedBookID = c.Int(nullable: false, identity: true),
                    CourseID = c.Int(nullable: false),
                    DepartmentID = c.Int(nullable: false),
                    Title = c.String(),
                    Author = c.String(),
                    PublicationDate = c.DateTime(nullable: false),
                })
            .PrimaryKey(t => t.RecommendedBookID)
            .ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: false) // was true on migration
            .ForeignKey("dbo.Department", t => t.DepartmentID, cascadeDelete: false) // was true on migration
            .Index(t => t.CourseID)
            .Index(t => t.DepartmentID);

    }

    public override void Down()
    {
        DropForeignKey("dbo.RecommendedBook", "DepartmentID", "dbo.Department");
        DropForeignKey("dbo.RecommendedBook", "CourseID", "dbo.Course");
        DropIndex("dbo.RecommendedBook", new[] { "DepartmentID" });
        DropIndex("dbo.RecommendedBook", new[] { "CourseID" });
        DropTable("dbo.RecommendedBook");
    }
}

जब आपका माइग्रेशन विफल हो जाता है तो आपको कुछ विकल्प दिए जाते हैं: 'परिचय कुंजी की बाधा' 'FK_dbo.RecommendedBook_dbo.Depbox_DepboxID' टेबल पर 'अनुशंसितबुक' चक्र या एकाधिक कैस्केड पथ का कारण हो सकता है। DELETE NO ACTION या UPDATE NO ACTION को निर्दिष्ट करें, या अन्य FOREIGN कुंजी बाधाओं को संशोधित करें। अड़चन या सूचकांक नहीं बना सका। पिछली त्रुटियों को देखें। '

यहाँ माइग्रेशन फ़ाइल में गलत 'cascadeDelete' को सेट करके 'फिर अन्य फॉरवर्ड डिजाइन की बाधाओं को संशोधित करने' और फिर 'अपडेट-डेटाबेस' चलाने का एक उदाहरण है।


0

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

माइग्रेशन हटाकर प्रारंभ करें, फिर अशक्त इंट की कोशिश करें।

समस्या एक संशोधन और मॉडल डिजाइन दोनों थी। कोई कोड परिवर्तन आवश्यक नहीं था।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.