नेविगेशन संपत्ति के बिना ईएफ कोड पहली विदेशी कुंजी


93

मान लीजिए कि मेरी निम्नलिखित इकाइयाँ हैं:

public class Parent
{
    public int Id { get; set; }
}
public class Child
{
    public int Id { get; set; }
    public int ParentId { get; set; }
}

कोड पहली धाराप्रवाह एपीआई सिंटैक्स लागू करने के लिए क्या है कि ParentId डेटाबेस में एक विदेशी कुंजी बाधा के साथ माता-पिता की मेज पर बनाया गया है, एक नेविगेशन संपत्ति की आवश्यकता के बिना ?

मुझे पता है कि अगर मैं एक नेविगेशन संपत्ति पेरेंट टू चाइल्ड जोड़ता हूं, तो मैं यह कर सकता हूं:

modelBuilder.Entity<Child>()
    .HasRequired<Parent>(c => c.Parent)
    .WithMany()
    .HasForeignKey(c => c.ParentId);

लेकिन मैं इस विशेष मामले में नेविगेशन संपत्ति नहीं चाहता।


1
मुझे नहीं लगता कि यह वास्तव में सिर्फ ईएफ के साथ संभव है, आपको इसे स्थापित करने के लिए मैन्युअल रूप से कुछ कच्चे एसक्यूएल का उपयोग करने की आवश्यकता है
प्यार नहीं किया।

@LukeMcGregor जो मुझे डर था। यदि आप ऐसा उत्तर देते हैं तो मुझे यह स्वीकार करते हुए खुशी होगी कि यह सही है। :-)
रेशनलगीक

क्या नेविगेशन संपत्ति नहीं होने का कोई विशेष कारण है? आपके लिए नेविगेशन प्रॉपर्टी को निजी काम बना देगा - इकाई के बाहर दिखाई नहीं देगा, लेकिन कृपया ईएफ करें। (ध्यान दें मैंने यह कोशिश नहीं की है, लेकिन मुझे लगता है कि यह काम करना चाहिए - निजी संपत्तियों के बारे में इस पोस्ट पर एक नज़र डालें romiller.com/2012/10/01/… )
Pawel

6
वैसे मुझे इसकी आवश्यकता नहीं है क्योंकि मुझे इसकी आवश्यकता नहीं है। मुझे किसी डिज़ाइन में अतिरिक्त अनावश्यक सामान रखना पसंद नहीं है, केवल एक रूपरेखा की आवश्यकताओं को पूरा करने के लिए। क्या यह मुझे नौसेना के प्रस्ताव में डालने के लिए मार डालेगा? वास्तव में, यही मैंने कुछ समय के लिए किया है।
राकेशगीक

संबंध बनाने के लिए आपको हमेशा कम से कम एक तरफ नेविगेशन प्रॉपर्टी की आवश्यकता होती है। अधिक जानकारी के लिए stackoverflow.com/a/7105288/105445
वाहिद बितर

जवाबों:


63

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

यदि आप कोड फर्स्ट माइग्रेशन का उपयोग कर रहे हैं तो आपके पास पैकेज मैनेजर कंसोल ( add-migration SomeNewSchemaName) पर एक नया कोड आधारित माइग्रेशन जोड़ने का विकल्प है । यदि आपने अपने मॉडल के साथ कुछ बदल दिया है या एक नया माइग्रेशन जोड़ा जाएगा। यदि आपने कुछ भी नहीं बदला है तो एक नए माइग्रेशन का उपयोग करके बाध्य करें add-migration -IgnoreChanges SomeNewSchemaName। माइग्रेशन में केवल इस मामले में रिक्त Upऔर Downविधियाँ होंगी ।

फिर आप Upइसमें follwing जोड़कर विधि को संशोधित कर सकते हैं :

public override void Up()
{
    // other stuff...

    AddForeignKey("ChildTableName", "ParentId", "ParentTableName", "Id",
        cascadeDelete: true); // or false
    CreateIndex("ChildTableName", "ParentId"); // if you want an index
}

इस माइग्रेशन update-databaseको चलाने ( पैकेज मैनेज कंसोल पर) इसी तरह (SQL सर्वर के लिए) एक SQL स्टेटमेंट चलाएगा:

ALTER TABLE [ChildTableName] ADD CONSTRAINT [FK_SomeName]
FOREIGN KEY ([ParentId]) REFERENCES [ParentTableName] ([Id])

CREATE INDEX [IX_SomeName] ON [ChildTableName] ([ParentId])

वैकल्पिक रूप से, माइग्रेशन के बिना, आप केवल एक शुद्ध SQL कमांड का उपयोग करके चला सकते हैं

context.Database.ExecuteSqlCommand(sql);

जहां contextआपके व्युत्पन्न संदर्भ वर्ग का एक उदाहरण है और sqlस्ट्रिंग के रूप में उपरोक्त SQL कमांड है।

विदित हो कि इस सब के साथ ईएफ का कोई सुराग नहीं है जो ParentIdएक विदेशी कुंजी है जो एक रिश्ते का वर्णन करती है। ईएफ इसे केवल एक साधारण स्केलर संपत्ति के रूप में मानेगा। किसी तरह सभी ऊपर केवल एक SQL प्रबंधन उपकरण खोलने और बाधा को हाथ से जोड़ने की तुलना में केवल एक अधिक जटिल और धीमा तरीका है।


2
स्वचालन से सरलीकरण आता है: मेरे पास अन्य वातावरण तक पहुंच नहीं है, जहां मेरा कोड तैनात है। कोड में इन परिवर्तनों को करने में सक्षम होना मेरे लिए अच्छा है। लेकिन मुझे
स्नार्क

मुझे लगता है कि आप केवल इकाई पर एक विशेषता सेट करते हैं, इसलिए मूल आईडी पर, बस जोड़ें [ForeignKey("ParentTableName")]। वह संपत्ति जो माता-पिता की मेज पर है, उसे लिंक करेगी। अब आपको एक हार्ड-कोडित तालिका नाम मिल गया है।
त्रिनको

2
यह स्पष्ट रूप से असंभव नहीं है, नीचे दी गई अन्य टिप्पणी को देखें क्यों यह भी सही उत्तर के रूप में चिह्नित है
इगोर Be

114

यद्यपि यह पोस्ट Entity Frameworkनहीं के लिए है Entity Framework Core, यह किसी ऐसे व्यक्ति के लिए उपयोगी हो सकता है जो एंटिटी फ्रेमवर्क कोर (मैं V1.1.2 का उपयोग कर रहा हूं) का उपयोग करके एक ही चीज प्राप्त करना चाहता हूं।

मुझे नेविगेशन गुणों की आवश्यकता नहीं है (हालांकि वे अच्छे हैं) क्योंकि मैं डीडीडी का अभ्यास कर रहा हूं और मैं चाहता हूं Parentऔर Childदो अलग-अलग मूल जड़ें हो। मैं चाहता हूं कि वे विदेशी कुंजी के माध्यम से एक-दूसरे से बात करने में सक्षम हों न कि बुनियादी ढांचा-विशिष्ट Entity Frameworkनेविगेशन गुणों के माध्यम से ।

आपको बस इतना करना है कि नेविगेशन गुणों का उपयोग किए बिना HasOneऔर WithManyउनका उपयोग किए बिना रिश्ते को एक तरफ कॉन्फ़िगर करना है (वे वहां बिल्कुल नहीं हैं)।

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}

    protected override void OnModelCreating(ModelBuilder builder)
    {
        ......

        builder.Entity<Parent>(b => {
            b.HasKey(p => p.Id);
            b.ToTable("Parent");
        });

        builder.Entity<Child>(b => {
            b.HasKey(c => c.Id);
            b.Property(c => c.ParentId).IsRequired();

            // Without referencing navigation properties (they're not there anyway)
            b.HasOne<Parent>()    // <---
                .WithMany()       // <---
                .HasForeignKey(c => c.ParentId);

            // Just for comparison, with navigation properties defined,
            // (let's say you call it Parent in the Child class and Children
            // collection in Parent class), you might have to configure them 
            // like:
            // b.HasOne(c => c.Parent)
            //     .WithMany(p => p.Children)
            //     .HasForeignKey(c => c.ParentId);

            b.ToTable("Child");
        });

        ......
    }
}

मैं इकाई के गुणों को कैसे कॉन्फ़िगर करूं, इस पर उदाहरण दे रहा हूं, लेकिन यहां सबसे महत्वपूर्ण है HasOne<>, WithMany()और HasForeignKey()

आशा है कि इससे सहायता मिलेगी।


9
यह EF Core के लिए सही उत्तर है, और DDD का अभ्यास करने वालों के लिए, यह एक MUST है।
थियागो सिल्वा

1
मैं इस बात पर स्पष्ट नहीं हूं कि नौसैनिक संपत्ति को हटाने के लिए क्या बदला है। क्या आप स्पष्ट कर सकते हैं?
andrew.rockwell

3
@ andrew.rockwell: इस पर HasOne<Parent>()और .WithMany()बच्चे के विन्यास को देखें। वे नेविगेशन गुणों का उल्लेख बिल्कुल नहीं करते हैं, क्योंकि किसी भी तरह से परिभाषित नेविगेशन गुण नहीं हैं। मैं अपने अपडेट के साथ इसे स्पष्ट करने की कोशिश करूंगा।
डेविड लियांग

बहुत बढ़िया। धन्यवाद @DavidLiang
andrew.rockwell

2
@ mirind4 ओपी में विशिष्ट कोड नमूने से असंबंधित है, अगर आप अलग-अलग मूल संस्थाओं को उनके संबंधित DB तालिकाओं के लिए मैप कर रहे हैं, तो DDD के अनुसार, उन मूल एंटाइटिस को केवल एक दूसरे को उनकी पहचान के माध्यम से संदर्भित करना चाहिए, और एक पूर्ण संदर्भ नहीं होना चाहिए अन्य एआर इकाई के लिए। वास्तव में, DDD में, आदिम प्रकार के साथ int / log / गाइड (विशेष रूप से AR इकाइयाँ) जैसे प्रॉप्स का उपयोग करने के बजाय एक ऑब्जेक्ट ऑब्जेक्ट की पहचान बनाना आम बात है, आदिम जुनून से बचना और विभिन्न ARs को मान के माध्यम से संस्थाओं को संदर्भित करने की अनुमति देना ऑब्जेक्ट आईडी प्रकार। एचटीएच
थियागो सिल्वा

21

उन लोगों के लिए छोटा संकेत, जो DataAnotations का उपयोग करना चाहते हैं और नेविगेशन प्रॉपर्टी को उजागर नहीं करना चाहते - उपयोग करें protected

public class Parent
{
    public int Id { get; set; }
}
public class Child
{
    public int Id { get; set; }
    public int ParentId { get; set; }

    protected virtual Parent Parent { get; set; }
}

Thats यह - के cascade:trueबाद के साथ विदेशी कुंजी Add-Migrationबनाया जाएगा।


1
यह निजी द्वारा भी कर सकते हैं
मार्क विटके

2
चाइल्ड बनाते समय आपको असाइन करना होगा Parentया बस ParentId?
जॉर्ज मौअर

5
@MarcWittke virtualगुण नहीं हो सकते private
LINQ

@GeorgeMauer: यह एक अच्छा सवाल है! तकनीकी रूप से या तो एक काम करेगा, लेकिन यह भी समस्या बन जाता है जब आपके पास इस तरह के असंगत कोड होते हैं, क्योंकि डेवलपर्स (विशेष रूप से नए कॉमर्स) यह सुनिश्चित नहीं करते हैं कि क्या पास करना है।
डेविड लिआंग

15

ईएफ कोर के मामले में आपको जरूरी नहीं कि एक नेविगेशन संपत्ति प्रदान की जाए। आप बस रिश्ते के एक तरफ एक विदेशी कुंजी प्रदान कर सकते हैं। धाराप्रवाह एपीआई के साथ एक सरल उदाहरण:

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace EFModeling.Configuring.FluentAPI.Samples.Relationships.NoNavigation
{
    class MyContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
             modelBuilder.Entity<Post>()
                .HasOne<Blog>()
                .WithMany()
                .HasForeignKey(p => p.BlogId);
        }
    }

    public class Blog
    {
         public int BlogId { get; set; }
         public string Url { get; set; }
    }

    public class Post
    {
         public int PostId { get; set; }
         public string Title { get; set; }
         public string Content { get; set; }

        public int BlogId { get; set; }
    }
}

2

मैं .Net Core 3.1, EntityFramework 3.1.3 का उपयोग कर रहा हूं। मैं चारों ओर खोज रहा हूं और मैं जिस समाधान के साथ आया था, उसके सामान्य संस्करण का उपयोग कर रहा था HasForeginKey<DependantEntityType>(e => e.ForeginKeyProperty)। आप इस तरह एक से एक संबंध बना सकते हैं:

builder.entity<Parent>()
.HasOne<Child>()
.WithOne<>()
.HasForeginKey<Child>(c => c.ParentId);

builder.entity<Child>()
    .Property(c => c.ParentId).IsRequired();

आशा है कि यह मदद करता है या कम से कम HasForeginKeyविधि का उपयोग करने के लिए कुछ अन्य विचार प्रदान करता है ।


0

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

और मेरे पास अलग माइग्रेशन ऐप है, जो माइग्रेशन के लिए उपयोग किया जाता है (मैं ऑटोमोबाइल का उपयोग करता हूं) और प्रारंभिक डीबी निर्माण। यह परियोजना स्पष्ट कारणों से सब कुछ संदर्भित करती है।

समाधान सी शैली है:

  • लिंक के माध्यम से माइग्रेशन प्रोजेक्ट के लिए लक्ष्य वर्ग के साथ "कॉपी" फ़ाइल ( altवीएस में कुंजी के साथ ड्रैग-एन-ड्रॉप )
  • निष्क्रिय संपत्ति (और FK विशेषता) के माध्यम से अक्षम करें #if _MIGRATION
  • माइग्रेशन ऐप में उस प्रीप्रोसेसर परिभाषा को सेट करें और मॉडल प्रोजेक्ट में सेट न करें, इसलिए यह कुछ भी संदर्भ नहीं देगा ( Contactउदाहरण के लिए क्लास के साथ असेंबली न करें )।

नमूना:

    public int? ContactId { get; set; }

#if _MIGRATION
    [ForeignKey(nameof(ContactId))]
    public Contact Contact { get; set; }
#endif

बेशक आपको उसी तरह से usingनिर्देश निष्क्रिय करना चाहिए और नाम स्थान बदलना चाहिए ।

उसके बाद सभी उपभोक्ता उस संपत्ति को हमेशा की तरह DB क्षेत्र में उपयोग कर सकते हैं (और यदि आवश्यक नहीं है तो अतिरिक्त असेंबली का संदर्भ न लें), लेकिन DB सर्वर को पता चलेगा कि यह FK है और कैस्केडिंग का उपयोग कर सकता है। बहुत गंदा घोल। लेकिन काम करता है।

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