Que signifie la fin principale d'une association dans une relation 1: 1 dans le cadre 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;}
}

J'essayais de le faire dans Entity Framework lorsque j'ai eu l'erreur:

Impossible de déterminer la fin principale d'une association entre les types «ConsoleApplication5.Boo» et «ConsoleApplication5.Foo». L'extrémité principale de cette association doit être explicitement configurée à l'aide de l'API fluide de la relation ou des annotations de données.

J'ai vu des questions sur StackOverflow avec une solution à cette erreur, mais je veux comprendre ce que signifie le terme "extrémité principale".


Réponses:


378

Dans une relation un à un, une extrémité doit être principale et la deuxième extrémité doit être dépendante. L'extrémité principale est celle qui sera insérée en premier et qui peut exister sans celle dépendante. La fin dépendante est celle qui doit être insérée après le principal car elle a une clé étrangère au principal.

Dans le cas d'un framework d'entité, FK en dépend doit également être son PK, donc dans votre cas, vous devez utiliser:

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

Ou cartographie courante

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

6
@Ladislav, je dois créer deux tables indépendantes qui ont toutes deux une référence facultative (une à une), je veux qu'elles aient chacune leur propre PK, comment est-ce possible? J'ai posté une question distincte .
Shimmy Weitzhandler

10
Vous ne savez pas combien d'heures il a fallu pour trouver une réponse à cette question - la documentation ms est POOOOOOP ty.
gangelo

1
Notez que vous devrez peut-être ajouter à l'aide de System.ComponentModel.DataAnnotations.Schema; obtenir ForeignKey dans VS2012
stuartdotnet

2
Est-ce à dire que Fooc'est le principal alors?
bflemi3

8
@ bflemi3 vous avez raison Booest la personne à charge, nécessite un Fooet obtient la clé étrangère. Fooest le principal et peut exister sans Boo.
Colin

182

Vous pouvez également utiliser l' [Required]attribut d'annotation de données pour résoudre ce problème:

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; }
}

Fooest requis pour Boo.


C'était correct pour mon code suivant où je voulais une carte entre les deux en tant qu'entité distincte classe publique Organisation {public int Id {get; ensemble; }} utilisateur de classe publique {public int Id {get; ensemble; }} classe publique UserGroup {[Key] public int Id {get; ensemble; } [Obligatoire] organisation virtuelle publique Organisation {get; ensemble; } [Obligatoire] utilisateur virtuel public Utilisateur {get; ensemble; }}
AndyM

J'utilise Oracle et aucune des API courantes ne fonctionne pour moi. Merci mec. Si simple.
CameronP

11
Sachez que lorsque vous utilisez cette solution, vous obtiendrez des exceptions de validation lorsque vous essayez de mettre à jour un Booque vous venez de récupérer de la base de données, sauf si vous déclenchez d'abord le chargement différé de la Foopropriété. entityframework.codeplex.com/SourceControl/network/forks/…
NathanAldenSr

2
ne devrait pas Boo Booêtre virtuel alors?
Simon_Weaver

1
@NathanAldenSr le lien est mauvais maintenant, comment faites-vous ce changement?
CamHart

9

Ceci fait référence à la réponse de @Ladislav Mrnka sur l'utilisation d'une API fluide pour configurer la relation un-à-un.

Eu une situation où avoir FK of dependent must be it's PK n'était pas possible.

Par exemple, Foo déjà une relation un-à-plusieurs avec 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;
}

Maintenant, nous devions ajouter une autre relation un à un entre Foo et 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;
}

Voici comment spécifier une relation un-à-un à l'aide d'une API fluide:

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

Notez que tout en ajoutant PrimaryBarIddoit être supprimé, comme nous le spécifions via une API fluide.

Notez également que le nom de la méthode [WithOptionalPrincipal()][1]est assez ironique. Dans ce cas, le principal est Bar. La description de WithOptionalDependent () sur msdn le rend plus clair.


2
Et si vous voulez réellement la PrimaryBarIdpropriété? C'est ridicule pour moi. Si j'ajoute la propriété et dis que c'est la clé étrangère, j'obtiens une erreur. Mais si je n'ai pas la propriété, EF la créera quand même. Quelle est la différence?
Chris Pratt

1
@ChrisPratt Cela peut ne pas sembler raisonnable. Je suis arrivé à ces solutions après traînée et erreur. N'a pas pu configurer le mappage un à un lorsque j'avais une PrimayBarIdpropriété dans l' Fooentité. Probablement la même solution que vous avez essayée. Des limitations dans EF peut-être?
Sudarshan_SMD

3
Ouais c'est ça. Je suis venu pour découvrir que EF à ce jour n'a jamais implémenté des index uniques. Par conséquent, le seul moyen disponible pour mapper un un à un consiste à utiliser la clé primaire de l'extrémité principale comme clé primaire de l'extrémité dépendante, car une clé primaire est par nature unique. En d'autres termes, ils l'ont à moitié implémenté et ont pris un raccourci qui dicte que vos tables doivent être conçues de manière non standard.
Chris Pratt
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.