In EF Code First, what is the syntax for self-referencing foreign keys?

ef-code-first entity-framework

Question

I'm attempting to refer to a foreign key in the Contact table that goes from SpouseId to Id. What syntax should I use to achieve this? I appear to be at a loss for examples. Thanks.

Such is the course I teach:

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

EDIT1 According to the link given by Joel Cunningham and Morteza's response I have included some more code.

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

Note: I also gave my Contact class's Spouse field the "[ForeignKey("SpouseId")]" attribute. Sadly, I continue to get the error message "Sequence includes more than one matching element."

EDIT2: These responses from Morteza are accurate. You may either mark a property as a "[ForeginKey("SpouseId")] for self-referencing foreign keys. OR use the example of a fluent API below. My unit test was the root cause of the issues I mentioned in a few of my comments. The database was created correctly by EF. I came across a useful link that explained how self-referencing foreign keys and auto-increment keys might lead to the problem "Unable to identify a correct ordering for dependent operations." This, I think, is the root of my issue. Hope someone can use this.

1
38
5/23/2017 11:47:05 AM

Accepted Answer

This sort of thing will function:

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

It has been added to ForeignKeyAttribute.System.ComponentModel.DataAnnotations via assembly of CTP5.

First Update: CTP5 Bug

Making a Self-Referencing Independent Organizations raises an error due to a problem in CTP5. Instead, use International Key Associations as a workaround (which is always recommended regardless).

Update II: Setting Up a Self Referencing Association Using Fluent API:

If you'd want, you can use utilize fluent API to do this:

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

Utilizing the Model:

using (var context = new Ctp5Context())
{
    Contact contact = new Contact()
    {
        Name = "Morteza",
        Spouse = new Contact()
        {
            Name = "Code-First"
        }
    };
    context.Contacts.Add(contact);
    context.SaveChanges();
}
57
1/27/2011 5:29:04 PM

Popular Answer

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


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow