简体   繁体   中英

Optional one to one relationship in EF 6

I am using Entity Framework 6 with code first.

The ideal scenario would be the User creates a PrintType (eg "Business Card") and then he created multiple Layouts for this PrintType (eg "Center", "Left") an finally he creates a template called "Business Card with flowers". As soon he is creating this template the program should create a default-layout for THIS template.

So there should be an optional FK that is only set when it is an default-layout for a template.

I hope you could follow me.

When I want to create a migration with the code below i get the following error:

Unable to determine the principal end of an association between the types 'xxx.Entities.Template' and 'xxx.Entities.Layout'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

public class PrintType
{
    public int Id { get; set; }
    public string Title { get; set; }

    public virtual ICollection<Template> Templates { get; set; }
    public virtual ICollection<Layout> Layouts { get; set; }
}

public class Layout
{
    public int Id { get; set; }
    public string Title { get; set; }

    [Required]
    public virtual PrintType PrintType { get; set; }
    public Template Template { get; set; }
}

public class Template
{
    public int Id { get; set; }
    public string Title { get; set; }

    [Required]
    public virtual PrintType PrintType { get; set; }

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

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Layout>().HasOptional(a => a.Template).WithOptionalDependent().WillCascadeOnDelete(false);
    }

If I am following you, you need a relation in Fluent API that makes your Foreign key optional, In your DbContext class you can get this done with FluentAPI like this:

Method 1:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<A>()
            .HasOptional(a => a.MyB)
            .WithOptionalDependent()
            .WillCascadeOnDelete(true); // or false depends
    }

Method 2:

and if you are going to set the default template and Layout yourself in your code, you can set the dependents to required. you can get this done by putting a Required annotation on your depended ends like this:

public class Layout
{
    public int Id { get; set; }
    public string Title { get; set; }

    [Required]
    public virtual PrintType PrintType { get; set; }
    public Template Template { get; set; }
}

and

public class Template
{
    public int Id { get; set; }
    public string Title { get; set; }

    [Required]
    public virtual PrintType PrintType { get; set; }
    [Required]
    public Layout Layout { get; set; }
}

and your Fluent API code to avoid cascade delete issue:

modelBuilder.Entity<Child1>()
    .HasRequired(c => c.navigationpropertyhere)
    .WithMany()
    .WillCascadeOnDelete(false);

modelBuilder.Entity<Child2>()
    .HasRequired(s => s.navigationpropertyhere)
    .WithMany()
    .WillCascadeOnDelete(false);

it gives you the flexibility to play with the non-required fields too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM