एंटिटी फ्रेमवर्क धाराप्रवाह एपीआई का उपयोग कर एक से एक वैकल्पिक संबंध


79

हम Entity Framework Code First का उपयोग करके एक से एक वैकल्पिक संबंधों का उपयोग करना चाहते हैं। हमारी दो संस्थाएँ हैं।

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

    public int? LoyaltyUserDetailId { get; set; }
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}

public class LoyaltyUserDetail
{
    public int Id { get; set; }
    public double? AvailablePoints { get; set; }

    public int PIIUserId { get; set; }
    public PIIUser PIIUser { get; set; }
}

PIIUserहो सकता है LoyaltyUserDetailलेकिन एक LoyaltyUserDetailहोना चाहिए PIIUser। हमने इन धाराप्रवाह दृष्टिकोण तकनीकों की कोशिश की।

modelBuilder.Entity<PIIUser>()
            .HasOptional(t => t.LoyaltyUserDetail)
            .WithOptionalPrincipal(t => t.PIIUser)
            .WillCascadeOnDelete(true);

इस दृष्टिकोण ने तालिका LoyaltyUserDetailIdमें विदेशी कुंजी नहीं PIIUsersबनाई।

उसके बाद हमने निम्नलिखित कोड की कोशिश की।

modelBuilder.Entity<LoyaltyUserDetail>()
            .HasRequired(t => t.PIIUser)
            .WithRequiredDependent(t => t.LoyaltyUserDetail);

लेकिन इस बार ईएफ ने इन 2 टेबलों में कोई विदेशी कुंजी नहीं बनाई।

क्या आपके पास इस मुद्दे के लिए कोई विचार है? हम इकाई ढांचे धाराप्रवाह एपीआई का उपयोग करके एक से एक वैकल्पिक संबंध कैसे बना सकते हैं?

जवाबों:


101

ईएफ कोड फर्स्ट सपोर्ट 1:1और 1:0..1रिलेशनशिप। उत्तरार्द्ध वह है जो आप खोज रहे हैं ("एक से शून्य या एक के लिए")।

धाराप्रवाह पर आपके प्रयास एक मामले में दोनों सिरों पर आवश्यक हैं और दूसरे में दोनों सिरों पर वैकल्पिक

आपको एक छोर पर वैकल्पिक और दूसरे पर आवश्यक है

यहाँ प्रोग्रामिंग ईएफ कोड पहली पुस्तक से एक उदाहरण है

modelBuilder.Entity<PersonPhoto>()
.HasRequired(p => p.PhotoOf)
.WithOptional(p => p.Photo);

PersonPhotoइकाई नामक एक नेविगेशन संपत्ति है PhotoOfएक है कि अंक Personप्रकार। Personप्रकार कहा जाता है एक नेविगेशन संपत्ति है Photoकरने के लिए है कि अंक PersonPhotoप्रकार।

दो संबंधित वर्गों में, आप प्रत्येक प्रकार की प्राथमिक कुंजी का उपयोग करते हैं , न कि विदेशी कुंजियों का । यानी, आप LoyaltyUserDetailIdया PIIUserIdगुणों का उपयोग नहीं करेंगे । इसके बजाय, संबंध Idदोनों प्रकार के क्षेत्रों पर निर्भर करता है ।

यदि आप ऊपर धाराप्रवाह एपीआई का उपयोग कर रहे हैं, तो आपको LoyaltyUser.Idएक विदेशी कुंजी के रूप में निर्दिष्ट करने की आवश्यकता नहीं है , ईएफ यह पता लगाएगा।

तो बिना अपने कोड को खुद को परखने के लिए (मुझे अपने सिर से ऐसा करने से नफरत है) ... मैं इसे आपके कोड में अनुवाद करूंगा

public class PIIUser
{
    public int Id { get; set; }    
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}

public class LoyaltyUserDetail
{
    public int Id { get; set; }
    public double? AvailablePoints { get; set; }    
    public PIIUser PIIUser { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  modelBuilder.Entity<LoyaltyUserDetail>()
  .HasRequired(lu => lu.PIIUser )
  .WithOptional(pi => pi.LoyaltyUserDetail );
}

यह कहना है कि LoyaltyUserDetails PIIUserसंपत्ति की आवश्यकता है और PIIUser की हैLoyaltyUserDetail संपत्ति वैकल्पिक है।

आप दूसरे छोर से शुरू कर सकते हैं:

modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);

जो अब कहता है कि PIIUser की LoyaltyUserDetailसंपत्ति वैकल्पिक है और LoyaltyUser की PIIUserसंपत्ति की आवश्यकता है।

आपको हमेशा एचएएस / साथ पैटर्न का उपयोग करना होगा।

HTH और FWIW, एक से एक (या एक से शून्य / एक) रिश्ते कोड में कॉन्फ़िगर करने के लिए सबसे भ्रामक रिश्तों में से एक हैं, इसलिए आप अकेले नहीं हैं! :)


1
क्या यह उस उपयोगकर्ता को सीमित नहीं करता है जिस पर FK फ़ील्ड चुनना है? (मुझे लगता है कि वह ऐसा चाहता है, लेकिन उसने वापस रिपोर्ट नहीं की है, इसलिए मुझे नहीं पता), क्योंकि ऐसा लगता है कि वह क्लास में मौजूद एफके फील्ड चाहता है।
फ्राँस बौमा

1
माना। यह EF कैसे काम करता है की एक सीमा है। 1: 1 और 1: 0..1 प्राथमिक कुंजियों पर निर्भर करता है। अन्यथा मुझे लगता है कि आप "अद्वितीय एफके" में भटक रहे हैं जो अभी भी ईएफ में समर्थित नहीं है। :( (आप एक db विशेषज्ञ के अधिक ... यह सही है ... यह वास्तव में एक अद्वितीय FK के बारे में है?) और नहीं के अनुसार आगामी Ef6 में होने जा रहा है: Unitframework.codeplex.com/workitem/299
जूली लर्मन

1
हां @FransBouma, हम PIIUserId और LoyaltUserId फ़ील्ड को विदेशी कुंजी के रूप में उपयोग करना चाहते थे। लेकिन EF ने हमें और जूली के उल्लेख के अनुसार इस संतृप्ति में सीमित कर दिया है। प्रतिक्रियाओं के लिए धन्यवाद।
İलक्काय urलकनूर

@JulieLerman आप क्यों उपयोग करते हैं WithOptional? साथ अलग क्या है WithRequiredDependentऔर WithRequiredOptional?
विली

1
वैकल्पिक संबंध के साथ वैकल्पिक बिंदु जो कि वैकल्पिक है, उदाहरण के लिए 0..1 (शून्य या एक) क्योंकि ओपी ने कहा कि "PIIUser में एक लॉयल्टीयूसरडेल हो सकता है"। और आपका भ्रम जो कि 2 वें प्रश्न की ओर ले जाता है, वह यह है कि आपने गलत शब्दों में से एक को गलत कर लिया है। ;) वे WithRequiredDependent और WithRequiredPrincipal हैं। क्या यह ज़्यादा सही लगता है? एक आवश्यक अंत की ओर इशारा करते हुए जो या तो आश्रित (उर्फ "बच्चा") या प्रमुख उर्फ ​​"माता-पिता" है। यहां तक ​​कि एक से एक रिश्ते में जहां दोनों समान हैं, ईएफ को प्रिंसिपल के रूप में और आश्रित के रूप में एक को संदर्भित करने की आवश्यकता है। HTH!
जूली लर्मन

27

जैसे आप के बीच एक-से-कई संबंध हैं, तो बस करना LoyaltyUserDetailऔर PIIUserताकि आप मानचित्रण होना चाहिए

modelBuilder.Entity<LoyaltyUserDetail>()
       .HasRequired(m => m.PIIUser )
       .WithMany()
       .HasForeignKey(c => c.LoyaltyUserDetailId);

ईएफ को आपकी ज़रूरत की सभी विदेशी कुंजी और बस बनाना चाहिए WithMany की परवाह नहीं करनी चाहिए !


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

1
@ClickOk मुझे पता है कि यह एक पुराना सवाल है और टिप्पणी है, लेकिन यह सही उत्तर नहीं है क्योंकि यह एक के रूप में कई का उपयोग करता है, यह एक से एक या एक से शून्य संबंध नहीं बनाता है
महमूद दरवेश

3

आपके कोड में कई चीजें गलत हैं।

एक 1: 1 संबंध या तो है: पी <-PK है, जहां एक पी पक्ष भी एक FK, या है पी <-FK + यूसी , जहां FK ओर एक गैर पी है और एक यूसी है। आपके कोड से पता चलता है कि आपके पास FK <-FK है , क्योंकि आपने दोनों पक्षों को एक FK परिभाषित किया है, लेकिन यह गलत है। मैं फिर PIIUserसे पीके पक्ष है और LoyaltyUserDetailएफके पक्ष है। इसका मतलब यह है PIIUserकि एक FK फ़ील्ड नहीं है, लेकिन LoyaltyUserDetailकरता है।

य द 1: 1 संबंध वैकल्पिक है, तो FK पक्ष के पास कम से कम 1 अशक्त क्षेत्र होना चाहिए।

ऊपर दिए गए pswg ने आपके प्रश्न का उत्तर दिया लेकिन एक गलती की है कि उसने PIIUser में एक FK को भी परिभाषित किया है, जो निश्चित रूप से गलत है जैसा कि मैंने ऊपर वर्णित किया है। अतः Nullable FK फ़ील्ड को LoyaltyUserDetailपरिभाषित करें, FK फ़ील्ड LoyaltyUserDetailको चिह्नित करने के लिए विशेषता को परिभाषित करें, लेकिन FK फ़ील्ड को निर्दिष्ट न करें PIIUser

आपको pswg की पोस्ट के नीचे वर्णित अपवाद मिलता है, क्योंकि कोई भी पक्ष PK पक्ष (सिद्धांत अंत) नहीं है।

EF 1: 1 पर बहुत अच्छा नहीं है क्योंकि यह अद्वितीय बाधाओं को संभालने में सक्षम नहीं है।मैं पहले कोड का कोई विशेषज्ञ नहीं हूं, इसलिए मुझे नहीं पता कि यह यूसी बनाने में सक्षम है या नहीं।

(संपादित करें) btw: A 1: 1 B (FK) का अर्थ है कि केवल 1 FK बाधा बनी है, B के लक्ष्य पर A के PK की ओर इशारा करते हुए, 2 नहीं।


3
public class User
{
    public int Id { get; set; }
    public int? LoyaltyUserId { get; set; }
    public virtual LoyaltyUser LoyaltyUser { get; set; }
}

public class LoyaltyUser
{
    public int Id { get; set; }
    public virtual User MainUser { get; set; }
}

        modelBuilder.Entity<User>()
            .HasOptional(x => x.LoyaltyUser)
            .WithOptionalDependent(c => c.MainUser)
            .WillCascadeOnDelete(false);

यह संदर्भ और विदेश कुंजी पर समस्या को हल करेगा

जब एक रिकॉर्ड अद्यतन या DELETING


यह अपेक्षा के अनुरूप काम नहीं करेगा। इसके परिणामस्वरूप माइग्रेशन कोड होता है जो लॉयल्टी यूसरआईड को विदेशी कुंजी के रूप में उपयोग नहीं करता है, इसलिए User.Id और LoyaltyUser.Id एक ही मूल्य के साथ समाप्त हो जाएगा, और LoyaltyUserId को खाली छोड़ दिया जाएगा।
एरॉन क्वीन

2

ForeignKeyगुण को गुण जोड़ने का प्रयास करें LoyaltyUserDetail:

public class PIIUser
{
    ...
    public int? LoyaltyUserDetailId { get; set; }
    [ForeignKey("LoyaltyUserDetailId")]
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
    ...
}

और PIIUserसंपत्ति:

public class LoyaltyUserDetail
{
    ...
    public int PIIUserId { get; set; }
    [ForeignKey("PIIUserId")]
    public PIIUser PIIUser { get; set; }
    ...
}

1
हमने इन सभी धाराप्रवाह एपीआई दृष्टिकोणों से पहले डेटा एनोटेशन की कोशिश की। लेकिन डेटा एनोटेशन काम नहीं किया। यदि आप ऊपर उल्लिखित डेटा एनोटेशन जोड़ते हैं, तो EF इस अपवाद को फेंकता है => 'LoyaltyUserDetail' और 'PIIUser' प्रकारों के बीच संबंध के मुख्य अंत को निर्धारित करने में असमर्थ। इस एसोसिएशन के प्रमुख अंत को स्पष्ट रूप से संबंध धाराप्रवाह एपीआई या डेटा एनोटेशन का उपयोग करके कॉन्फ़िगर किया जाना चाहिए।
Ilkay ilknur

@ Iflkayİlknur यदि आप ForeignKeyसंबंध के केवल एक छोर पर विशेषता जोड़ते हैं तो क्या होगा ? पर ही PIIUser या LoyaltyUserDetail
pswg

Ef उसी अपवाद को फेंकता है।
Ilkay ilknur

1
@ PswU क्यों PIIUser पर FK? LoyaltyUserDetail में FK है, PIIUser नहीं। तो यह LoyaltyUserDetail की PIIUserId संपत्ति में [Key, ForeignKey ("PIIUser")] होना चाहिए। प्रयास करें इस
user808128

@ user808128 आप एनोटेशन को या तो नेविगेशन प्रॉपर्टी या आईडी पर रख सकते हैं, कोई अंतर नहीं।
थॉमस बोबी

1

उपरोक्त समाधानों के साथ भ्रमित करने वाली एक बात यह है कि प्राथमिक कुंजी को दोनों तालिकाओं में " आईडी" के रूप में परिभाषित किया गया है और यदि आपके पास तालिका नाम के आधार पर प्राथमिक कुंजी है तो यह काम नहीं करेगा, मैंने वर्गों को संशोधित किया है। यानी वैकल्पिक तालिका को यह परिभाषित नहीं करना चाहिए कि यह मुख्य तालिका से उसी कुंजी नाम का उपयोग करना चाहिए।

public class PIIUser
{
    // For illustration purpose I have named the PK as PIIUserId instead of Id
    // public int Id { get; set; }
    public int PIIUserId { get; set; }

    public int? LoyaltyUserDetailId { get; set; }
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}

public class LoyaltyUserDetail
{
    // Note: You cannot define a new Primary key separately as it would create one to many relationship
    // public int LoyaltyUserDetailId { get; set; }

    // Instead you would reuse the PIIUserId from the primary table, and you can mark this as Primary Key as well as foreign key to PIIUser table
    public int PIIUserId { get; set; } 
    public double? AvailablePoints { get; set; }

    public int PIIUserId { get; set; }
    public PIIUser PIIUser { get; set; }
}

और फिर उसके बाद

modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);

चाल चलेंगे, स्वीकृत समाधान स्पष्ट रूप से यह स्पष्ट करने में विफल रहता है, और इसने कारण जानने के लिए मुझे कुछ घंटों के लिए फेंक दिया


1

यह मूल पोस्टर से कोई फायदा नहीं है, लेकिन ईएफ 6 पर किसी के लिए भी, जिसे विदेशी कुंजी को प्राथमिक कुंजी से अलग करने की आवश्यकता है, यहां बताया गया है कि यह कैसे करना है:

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

    //public int? LoyaltyUserDetailId { get; set; }
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}

public class LoyaltyUserDetail
{
    public int Id { get; set; }
    public double? AvailablePoints { get; set; }

    public int PIIUserId { get; set; }
    public PIIUser PIIUser { get; set; }
}

modelBuilder.Entity<PIIUser>()
    .HasRequired(t => t.LoyaltyUserDetail)
    .WithOptional(t => t.PIIUser)
    .Map(m => m.MapKey("LoyaltyUserDetailId"));

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

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