web-dev-qa-db-fra.com

Quelle est la syntaxe pour l'auto-référencement de clés étrangères dans EF Code First?

J'essaie de référencer une clé étrangère de SpouseId à Id dans la table Contact. Quelle est la syntaxe pour cela? Je n'arrive pas à trouver un exemple. Merci.

J'ai une classe comme ça:

public class Contact
{
    public int Id {get;set;}
    public string Name {get;set;}
    public int? SpouseId {get;set;}
}

EDIT1 Selon le lien fourni par Joel Cunningham et la réponse de Morteza, j'ai ajouté du code supplémentaire.

ContactMap.cs

public partial class ContactMap : EntityTypeConfiguration<Contact>
{
  public ContactMap()
     {
       this.ToTable("Contact");
       this.HasKey(c => c.Id);
       this.HasOptional(c => c.Spouse)
           .WithMany()
           .IsIndependent()
           .Map(m => m.MapKey(fk => fk.Id, "SpouseId"));
     }
}

MyObjectContext.cs

public class MyObjectContext : DbContext, IDbContext
{
  public DbSet<Contact> Contacts {get;set;}
  protected override void OnModelCreating(ModelBuilder modelBuilder)
     {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Configurations.Add(new ContactMap());
     }
}

Remarque: J'ai également ajouté l'attribut "[ForeignKey (" SpouseId ")]" "à ma propriété Spouse dans ma classe Contact. Malheureusement, je reçois toujours "La séquence contient plus d'un élément correspondant".

EDIT2: Les réponses de Morteza ci-dessous sont correctes. Pour résumer: Pour les clés étrangères auto-référencées, vous pouvez soit marquer la propriété en tant que "[ForeginKey (" SpouseId ")] OR utilisez l'exemple d'API fluide ci-dessous. Les erreurs que j'ai signalées dans certaines de mes les commentaires ont été causés par mon test unitaire. EF a généré la base de données correctement. J'ai trouvé un bon lienCraig Stuntz a expliqué pourquoi les touches d'incrémentation automatique et l'auto -la référence de clés étrangères peut provoquer l'erreur "Impossible de déterminer un ordre valide pour les opérations dépendantes". Je crois que c'est mon problème. J'espère que cela aide quelqu'un.

38
trevorc

Quelque chose comme ça fonctionnera:

public class Contact
{
    public int Id {get;set;}
    public string Name {get;set;}
    public int? SpouseId {get;set;}

    [ForeignKey("SpouseId")]
    public Contact Spouse {get;set;}
}

ForeignKeyAttribute a été ajouté à System.ComponentModel.DataAnnotations par l'Assemblée CTP5.

Mise à jour I: bogue CTP5:

En raison d'un bogue dans CTP5, la création d'une association d'auto-référencement indépendante lève une exception. La solution consiste à utiliser les associations de clés étrangères à la place (ce qui est toujours recommandé malgré tout).

Mise à jour II: utilisation de l'API Fluent pour configurer une association d'auto-référencement:

Vous pouvez également utiliser une API fluide pour y parvenir, si vous préférez:

public class Contact
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? SpouseId { get; set; }                

    public Contact Spouse { get; set; }
}

public class Ctp5Context : DbContext
{
    public DbSet<Contact> Contacts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Contact>()
                    .HasOptional(c => c.Spouse)
                    .WithMany()
                    .HasForeignKey(c => c.SpouseId);
    }
}

Travailler avec le modèle:

using (var context = new Ctp5Context())
{
    Contact contact = new Contact()
    {
        Name = "Morteza",
        Spouse = new Contact()
        {
            Name = "Code-First"
        }
    };
    context.Contacts.Add(contact);
    context.SaveChanges();
}
56
Morteza Manavi
[Table("Move")]
public class Move
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long ID { get; set; }
    public long? ParentID { get; set; }

    [InverseProperty("Children")]
    public virtual Move Parent { get; set; }
    public virtual ICollection<Move> Children { get; set; }
}
6
Ali Bah

De plus, la propriété de navigation Spouse doit être virtuelle pour éviter les requêtes JOIN inutiles:

 public virtual Contact Spouse { get; set; }
4
ReflexiveCode