kexx
kexx

Reputation: 285

InvalidOperationException during EF6 code-first database initialization (principal end of this association must be explicitly configured)

I'm using EF6 and code-first approach to implement custom properties for products belongs to certain categories (or any other classification tree: aspect). I'd like to implement the following database structure through components.

desired database structure

Direct link to the image: image

(The relation links moved to the corresponding primary/foreign key in the image)

When I added the AssignedOption navigational property to the Aspects class/table, I got the following exception during seeding:

"Unable to determine the principal end of an association between the types 'storeBeacon.Models.Aspect' and 'storeBeacon.Models.AspectOption'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations."

The code of the related classes are the following:

Public Class Aspect

    <Key>
    Public Property Id As Integer

    Public Property Name As String

    Public Property Type As String

    Public Property CardinalityMinimum As Byte

    Public Property CardinalityMaximum As Byte


    <ForeignKey("AssignedOptionId")>
    Public Overridable Property AssignedOption As AspectOption
    Public Property AssignedOptionId As Integer?

End Class

Public Class AspectOption


    <Key>
    Public Property Id As Integer

    <ForeignKey("AspectId")>
    Public Overridable Property Aspect As Aspect
    Public Property AspectId As Integer


    <ForeignKey("ParentId")>
    Public Overridable Property Parent As AspectOption
    Public Property ParentId As Integer?

    Public Property Label As String


End Class

So can you please tell me how to fix this problem without fluent API if possible?

Upvotes: 1

Views: 213

Answers (1)

Corey Adler
Corey Adler

Reputation: 16149

It looks like you're trying to set them up as a one-to-one relationship. In which case you'll need to pick one of them to be the primary table of the relationship, and the other to use a FK into it. Because right now you can't use 2 FKs to point to each other, since it confuses Entity Framework.

EDIT: Based on the comment, I've figured out what you need to do. I wrote my code in C#, but I'm sure it's easily translatable to VB.

In Aspect:

public int AssignedOptionID { get; set; }

[ForeignKey("AssignedOptionID"), InverseProperty("Aspects")]
public virtual AspectOption AssignedOption { get; set; }

public virtual List<AspectOption> AspectOptions { get; set; } 

In AspectOption:

[ForeignKey("AspectID"), InverseProperty("AspectOptions")]
public virtual Aspect Aspect { get; set; }

[ForeignKey("ParentID")]
public virtual AspectOption Parent { get; set; }

public virtual List<Aspect> Aspects { get; set; } 

In your DbContext's OnModelCreating method (yes, you have to do something in Fluent API, since otherwise it will throw an exception saying that there are multiple cascade paths):

modelBuilder.Entity<Aspect>()
            .HasMany(a => a.AspectOptions)
            .WithRequired(a => a.Aspect)
            .WillCascadeOnDelete(false);

Upvotes: 2

Related Questions