0

The following is an simplified example of a parent/child relationship I'm trying to get working in Entity Framework code-first. The parent has a list of children, and one of them is selected as the default:

public class Parent
{
    [Key]
    public int Id { get; set; }
    public virtual Child DefaultChild { get; set; }          // One-to-One
    public virtual ICollection<Child> Children { get; set; } // One-to-Many
}

public class Child
{
    [Key]
    public int Id { get; set; }
    [Required]
    public virtual Parent Parent { get; set; }
}

When I run entity framework's add-migration command, it is setting the Id for Child as a key, however, instead of making it an IDENTITY it is using a Foreign Key reference to the parent Id.

I tried doing the following on my DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Parent>().HasOptional(p => p.DefaultChild).WithRequired(c => c.Parent);
    modelBuilder.Entity<Parent>().HasMany(p => p.Children).WithRequired(c => c.Parent);
    base.OnModelCreating(modelBuilder);
} 

However, then it tosses this error: Schema specified is not valid. Errors: The relationship 'Sample.Presentation.DataAccess.Parent_DefaultChild' was not loaded because the type 'Sample.Presentation.DataAccess.Child' is not available.

How are you supposed to handle these relationships?

I know I could add a boolean flag to the Child (e.g. IsDefault) and get rid of the DefaultChild relationship on the parent. However, I'd like to avoid that if possible.


Edit: I found this info on StackOverflow utilizing WithOptionalPrincipal, however, it creates an additional ParentId field on the child as opposed to creating the ChildId on the parent?! Not quite what I want.


Edit: Added DatabaseGenerated as suggested in comments. This is what the migrations output:

CreateTable(
    "dbo.Children",
    c => new
       {
           Id = c.Int(nullable: false, identity: true),
           Parent_Id = c.Int(nullable: false),
       })
       .PrimaryKey(t => t.Id)
       .ForeignKey("dbo.Parents", t => t.Id)  // <== I don't want this!
       .ForeignKey("dbo.Parents", t => t.Parent_Id, cascadeDelete: true)
       .Index(t => t.Id)
       .Index(t => t.Parent_Id);

 CreateTable(
    "dbo.Parents",
    c => new
       {
           Id = c.Int(nullable: false, identity: true)  // <== I expect DefaultChildId after this
       })
       .PrimaryKey(t => t.Id);  // <== and a foreign key referencing Child.Id
Community
  • 1
  • 1
Sam
  • 9,933
  • 12
  • 68
  • 104
  • Not sure, why this is happening, you can explicitly try setting DatabaseGenerated to DatabaseGenerationOption.Identity. May be that can work. – Ashish Charan Jan 03 '14 at 07:25
  • Tried you suggestion and it set identity to true, but still referenced the parent table as a foreign key. See new edit. – Sam Jan 03 '14 at 07:36
  • By default,if the type of the key property is integer,EF will set the key as identity.As I mentioned below,EF requires the Foreign key and the primary key to be the same field(in the dependent end). – york Jan 03 '14 at 08:02

1 Answers1

1

An one-to-one and an one-to-many relationship can not coexist on two entities.Because EF requires the key of the dependent end(should have foreign key) of an one-to-one relationship must be the foreign key to the principal end.This rule makes sure an one-to-one relationship work.I think it's an available solution to add a property,IsDefault,to the Child entity.

york
  • 108
  • 8
  • You are right, but maybe you can show an alternative mapping to make it more clear. The point is that `WithRequired(c => c.Parent)` is used twice. – Gert Arnold Jan 03 '14 at 08:58
  • Found a solution that was mostly what I wanted. Only thing is that I have to include the Foreign Keys on my models: http://stackoverflow.com/questions/5346870/entity-framework-code-first-how-can-i-create-a-one-to-many-and-a-one-to-one-rel – Sam Jan 03 '14 at 13:46