Cosa significa fine principale di un'associazione nella relazione 1: 1 nel framework Entity


269
public class Foo
{
    public string FooId{get;set;}
    public Boo Boo{get;set;}
}


public class Boo
{
    public string BooId{get;set;}
    public Foo Foo{get;set;}
}

Stavo provando a farlo in Entity Framework quando ho ricevuto l'errore:

Impossibile determinare la fine principale di un'associazione tra i tipi "ConsoleApplication5.Boo" e "ConsoleApplication5.Foo". L'estremità principale di questa associazione deve essere configurata esplicitamente utilizzando l'API fluente della relazione o le annotazioni dei dati.

Ho visto domande su StackOverflow con una soluzione per questo errore, ma voglio capire cosa significa il termine "fine principale".


Risposte:


378

Nella relazione uno a uno un'estremità deve essere principale e la seconda estremità deve essere dipendente. Il fine principale è quello che verrà inserito per primo e che può esistere senza quello dipendente. L'estremità dipendente è quella che deve essere inserita dopo il principale perché ha una chiave esterna per il principale.

Nel caso di framework di entità FK in dipendenza deve essere anche il suo PK, quindi nel tuo caso dovresti usare:

public class Boo
{
    [Key, ForeignKey("Foo")]
    public string BooId{get;set;}
    public Foo Foo{get;set;}
}

O mappatura fluida

modelBuilder.Entity<Foo>()
            .HasOptional(f => f.Boo)
            .WithRequired(s => s.Foo);

6
@Ladislav, devo creare due tabelle indipendenti che hanno entrambe un riferimento facoltativo (una a una), voglio che entrambe abbiano i loro PK ciascuno, come è possibile? Ho pubblicato una domanda separata .
Shimmy Weitzhandler,

10
Non hai idea di quante ore ci sono volute per trovare una risposta a questa - la documentazione di ms è POOOOOOP ty.
gangelo,

1
Nota potrebbe essere necessario aggiungere utilizzando System.ComponentModel.DataAnnotations.Schema; ottenere ForeignKey in VS2012
stuartdotnet,

2
Vuol dire che allora Fooè il principale?
bflemi3,

8
@ bflemi3 hai ragione Booè il dipendente, richiede un Fooe ottiene la chiave esterna. Fooè il principale e può esistere senza a Boo.
Colin,

182

Puoi anche usare l' [Required]attributo di annotazione dei dati per risolvere questo:

public class Foo
{
    public string FooId { get; set; }

    public Boo Boo { get; set; }
}

public class Boo
{
    public string BooId { get; set; }

    [Required]
    public Foo Foo {get; set; }
}

Fooè richiesto per Boo.


Questo era corretto per il mio codice seguente in cui desideravo una mappa tra i due come entità pubblica di classe separata Organization {public int Id {get; impostato; }} utente di classe pubblica {id pubblico int {get; impostato; }} gruppo di utenti di classe pubblica {[Key] public int Id {get; impostato; } [Obbligatorio] Organizzazione virtuale pubblica Organizzazione {get; impostato; } [Richiesto] Utente utente pubblico virtuale {get; impostato; }}
AndyM,

Sto usando Oracle e nessuna delle API fluenti ha funzionato per me. Grazie fratello Così semplice.
CameronP

11
Tenere presente che quando si utilizza questa soluzione si ottengono eccezioni di convalida quando si tenta di aggiornare un oggetto Booappena recuperato dal database, a meno che non si attivi prima il caricamento lento della Fooproprietà. entityframework.codeplex.com/SourceControl/network/forks/…
NathanAldenSr

2
non dovrebbe Boo Booessere virtuale allora?
Simon_Weaver

1
@NathanAldenSr il link non funziona adesso, come si fa a cambiare?
CamHart

9

Questo è in riferimento alla risposta di @Ladislav Mrnka sull'uso di API fluenti per la configurazione della relazione uno a uno.

Ha avuto una situazione in cui FK of dependent must be it's PKnon era fattibile.

Ad esempio, Fooha già una relazione uno-a-molti con Bar.

public class Foo {
   public Guid FooId;
   public virtual ICollection<> Bars; 
}
public class Bar {
   //PK
   public Guid BarId;
   //FK to Foo
   public Guid FooId;
   public virtual Foo Foo;
}

Ora, abbiamo dovuto aggiungere un'altra relazione uno a uno tra Foo e Bar.

public class Foo {
   public Guid FooId;
   public Guid PrimaryBarId;// needs to be removed(from entity),as we specify it in fluent api
   public virtual Bar PrimaryBar;
   public virtual ICollection<> Bars;
}
public class Bar {
   public Guid BarId;
   public Guid FooId;
   public virtual Foo PrimaryBarOfFoo;
   public virtual Foo Foo;
}

Ecco come specificare una relazione uno a uno usando api fluente:

modelBuilder.Entity<Bar>()
            .HasOptional(p => p.PrimaryBarOfFoo)
            .WithOptionalPrincipal(o => o.PrimaryBar)
            .Map(x => x.MapKey("PrimaryBarId"));

Si noti che durante l'aggiunta PrimaryBarIddeve essere rimosso, poiché lo specifichiamo tramite API fluente.

Si noti inoltre che il nome del metodo [WithOptionalPrincipal()][1]è un po 'ironico. In questo caso, Principal è Bar. La descrizione WithOptionalDependent () su msdn lo rende più chiaro.


2
Cosa succede se si desidera effettivamente la PrimaryBarIdproprietà? Questo è ridicolo per me. Se aggiungo la proprietà e dico che è la chiave esterna, viene visualizzato un errore. Ma se non ho la proprietà, EF lo creerà comunque. Qual è la differenza?
Chris Pratt,

1
@ChrisPratt Potrebbe non sembrare ragionevole. Sono arrivato a queste soluzioni dopo il trail e l'errore. Non ero in grado di configurare il mapping uno a uno quando avevo la PrimayBarIdproprietà Foonell'entità. Probabilmente la stessa soluzione che hai provato. Limitazioni in EF forse?
Sudarshan_SMD

3
Si lo è. Sono venuto a scoprire che EF fino ad oggi non ha mai implementato indici univoci. Di conseguenza, l'unico modo disponibile per mappare uno a uno è utilizzare la chiave primaria dell'estremità principale come chiave primaria dell'estremità dipendente, poiché una chiave primaria è per sua natura unica. In altre parole, l'hanno implementato a metà e hanno preso una scorciatoia che impone che i tavoli debbano essere progettati in modo non standard.
Chris Pratt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.