2013-01-23 12 views
34

इस समस्या के बारे में बहुत सारे प्रश्न हैं, लेकिन मैं अपने मामले को हल नहीं कर सका। कुछ एक कृपया इस पर एक नज़र ले जा सकते हैं:इकाई फ्रेमवर्क: कैसे हल करें "विदेशी कुंजी बाधा चक्र या एकाधिक कैस्केड पथ का कारण बन सकती है"?

मैं एक Office तालिका जो Doctor और Secretary तालिकाओं के साथ एक-अनेक संबंध है है। दोनों अंतिम सारणीएं Employee तालिका से ली गई हैं जिनमें sqlmembershipprovider द्वारा बनाई गई पूर्वनिर्धारित Users तालिका के साथ साझा-प्राथमिक-कुंजी संबंध है। ऐसा लगता है कि Users तालिका और Roles तालिका के बीच कई सारे रिश्ते हैं जिनके पास मेरे पास कोई हाथ नहीं है।

मेरी समस्या एक (शून्य, एक) - (एक) मेरे Employee तालिका और Users तालिका के बीच संबंध बनाने में थी जो मैंने उनके बीच साझा प्राथमिक कुंजी संबंध और समाप्त हुई त्रुटि के साथ समाप्त किया था। (वहाँ है कि समस्या के लिए एक बेहतर समाधान है?)

यहाँ त्रुटि है:

public class Office 
{ 
    public Office() 
    { 
     this.Doctors = new HashSet<Doctor>(); 
     this.Secretaries = new HashSet<Secretary>(); 
    } 

    [Key] 
    public System.Guid OfficeId { get; set; } 
    public virtual ICollection<Doctor> Doctors { get; set; } 
    public virtual ICollection<Secretary> Secretaries { get; set; } 
} 

public class Employee 
{ 
    [Key, ForeignKey("User")] 
    [DatabaseGenerated(DatabaseGeneratedOption.None)] 
    public System.Guid Id { get; set; } 
    public string Name { get; set; } 

    [ForeignKey("Office")] 
    public System.Guid OfficeId { get; set; } 

    // shared primary key 
    public virtual aspnet_Users User { get; set; } 

    public virtual Office Office { get; set; } 
} 

public class Doctor :Employee 
{ 
    public Doctor() 
    { 
     this.Expertises = new HashSet<Expertise>(); 
    } 
    //the rest..  
    public virtual ICollection<Expertise> Expertises { get; set; } 
} 

public class Secretary : Employee 
{ 
    // blah blah 
} 

public class aspnet_Users 
{ 
    public aspnet_Users() 
    { 
     this.aspnet_Roles = new List<aspnet_Roles>(); 
    } 

    public System.Guid ApplicationId { get; set; } 
    public System.Guid UserId { get; set; } 
    //the rest.. 
    public virtual aspnet_Applications aspnet_Applications { get; set; } 
    public virtual ICollection<aspnet_Roles> aspnet_Roles { get; set; } 
} 

public class aspnet_Roles 
{ 
    public aspnet_Roles() 
    { 
     this.aspnet_Users = new List<aspnet_Users>(); 
    } 

    public System.Guid ApplicationId { get; set; } 
    public System.Guid RoleId { get; set; } 
    //the rest.. 
    public virtual aspnet_Applications aspnet_Applications { get; set; } 
    public virtual ICollection<aspnet_Users> aspnet_Users { get; set; } 
} 

:

Introducing FOREIGN KEY constraint 'FK_dbo.aspnet_UsersInRoles_dbo.aspnet_Users_UserId' on table 'aspnet_UsersInRoles' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors.

यहाँ मेरी कोड और रिवर्स इंजीनियरिंग के बाद सदस्यता कोड हैं संपादित करें: और रिश्ते गहरे हो जाते हैं, Users तालिका औरके बीच कई-एक संबंध हैंतालिका, Roles और Applications के बीच भी।

+0

मुझे यह अधिकार प्राप्त करते हैं, तो आप कर्मचारी और उपयोगकर्ता तालिका में पी के लिए एक ही मूल्य का उपयोग कर रहे हैं: ऐसा करने का अपडेट किया गया जिस तरह से Entityframework कोर के लिए इस प्रकार 1,0

table.ForeignKey(name: "FK_Cities_Regions_RegionId", column: x => x.RegionId, principalTable: "Regions", principalColumn: "RegionId", onDelete: ReferentialAction.NoAction); 

नोट के रूप में है? –

+0

हां, जैसा कि मुझे उम्मीद है कि पहले उपयोगकर्ता मान होना चाहिए, तो मैं इसे कर्मचारी में उपयोग करता हूं। त्रुटि केवल शुरुआत में उठाती है। – Blazi

उत्तर

66

त्रुटि संदेश सुझाए गए कार्यों को निर्दिष्ट करने के लिए आप धाराप्रवाह एपीआई का उपयोग कर सकते हैं।

अपने संदर्भ में:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
     base.OnModelCreating(modelBuilder); 
     modelBuilder.Entity<aspnet_UsersInRoles>().HasMany(i => i.Users).WithRequired().WillCascadeOnDelete(false); 
} 

ध्यान दें कि आप तालिका aspnet_UsersInRoles के लिए परिभाषा शामिल नहीं किया है तो यह कोड काम न करें।

एक अन्य विकल्प मेरा सुझाव है http://msdn.microsoft.com/en-US/data/jj591620

+0

हाय चार्ल्स। मैं 'उपयोगकर्ता' या 'भूमिका' या 'उपयोगकर्ताइनरोल' में हेरफेर नहीं कर सकता क्योंकि तब सदस्यता प्रदाता काम करना बंद कर देगा। क्या मैं अपनी टेबल में कहीं सर्कल बदल सकता हूं? – Blazi

+0

अच्छी तरह से ईएफ उन तालिकाओं को संशोधित करने की कोशिश कर रहा है। आपकी त्रुटि ईएफ से एक विदेशी कुंजी बाधा जोड़ने की कोशिश कर रही है। Aspnet_ * वर्ग परिभाषाओं में से प्रत्येक को [NotMapped] जोड़ने का प्रयास करें। यह आपको कक्षाओं का उपयोग करने की अनुमति देगा लेकिन ईएफ उनके लिए टेबल बनाने की कोशिश नहीं करेगा। – Charles

+0

WillCascadeOnDelete (झूठी) इस उत्तर की कुंजी है। धन्यवाद – nadav

3

अपनी टिप्पणी के आधार पर दूर करने के लिए इस

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 

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

इस तरह आप अपनी संरचना को वही रखते हैं और आप चक्र से छुटकारा पा सकते हैं।

20

इसके अलावा आप अपनी माइग्रेशन क्लास को संशोधित कर सकते हैं। माइग्रेशन कक्षा में मेरे मामले में किया गया था:

CreateTable(
    "dbo.Spendings", 
    c => new 
     { 
      SpendingId = c.Int(nullable: false, identity: true), 
      CategoryGroupId = c.Int(nullable: false), 
      CategoryId = c.Int(nullable: false), 
      Sum = c.Single(nullable: false), 
      Date = c.DateTime(nullable: false), 
      Comment = c.String(), 
      UserId = c.String(), 
      LastUpdate = c.String(), 
     }) 
    .PrimaryKey(t => t.SpendingId) 
    .ForeignKey("dbo.Categories", t => t.CategoryId, cascadeDelete: true) 
    .ForeignKey("dbo.CategoryGroups", t => t.CategoryGroupId, cascadeDelete: true) 
    .Index(t => t.CategoryGroupId) 
    .Index(t => t.CategoryId); 

को हटाने के बाद "cascadeDelete: सच" अद्यतन-डाटाबेस पूरी तरह से काम करता है।

या के रूप में false

.ForeignKey("dbo.Categories", t => t.CategoryId, cascadeDelete: false) 
7
protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
    } 

संदर्भ

+3

क्या मैं इसका उपयोग करना चाहता हूं? इसका किस तरह के नकारात्मक प्रभाव हो सकते हैं? – rotgers

+0

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

1

में यह कोड जोड़ें बस एक अद्यतन:

अन्य उत्तर आप नहीं हटा पर कोई कार्रवाई करने की जरूरत है पता चलता है कि। ReferentialAction.NoActiononDelete