简体   繁体   中英

How to prevent Entity Framework from creating double Foreign Keys

i'm having trouble with creating a database from my entities using code first. Please consider the two classes. CourseTn class

    public class CourseTn
{
    // Pk
    public CourseLevel CourseTnId { get; set; }

    // Properties
    public string Title { get; set; }
    public virtual List<CourseTnImage> CourseImage { get; set; }
    public virtual List<ChapterTn> Chapters { get; set; }

    public AdministratorTnAccount AdministratorTnAccount { get; set; }
    public Guid? AdministratorTnAccountId { get; set; }

    public ClientTnAccount ClientTnAccount { get; set; }
    public Guid? ClientTnAccountId { get; set; }

}

and the ChapterTn class

public class ChapterTn
{
    // Pk
    public int ChapterTnId { get; set; }

    // Properties
    public string ChapterName { get; set; }
    public virtual List<ChapterTnImage> ChapterImage { get; set; }
    public virtual List<SectionTn> Sections { get; set; }

    // FK

    public virtual CourseTn CourseTn { get; set; }
    public CourseLevel CourseTnId { get; set; }
}

The courseTnId is specified within the chapterTn class as a foreign key. The first issue is that the Entitiy Framework doesnt seem to recorgnis this convention, and maps courseTnId as a proptery instead.

The second issue is that the Enitity Framework creates two FK for the courseTn, one is null and the other is not null. Please see bellow image

在此处输入图片说明

Is there a way to make make Entity Framework recognise the conventional specified FK of courseTnId in the chapterTn class ?

Your PK can't be complex type CourseLevel . And same for your FK. Try the below:

    public class CourseTn
    {
        // Pk
        public int CourseTnId { get; set; }

        // Properties
        public string Title { get; set; }
        public virtual List<CourseTnImage> CourseImage { get; set; }
        public virtual List<ChapterTn> Chapters { get; set; }

        public AdministratorTnAccount AdministratorTnAccount { get; set; }
        public Guid? AdministratorTnAccountId { get; set; }

        public ClientTnAccount ClientTnAccount { get; set; }
        public Guid? ClientTnAccountId { get; set; }

    }

    public class ChapterTn
    {
        // Pk
        public int ChapterTnId { get; set; }

        // Properties
        public string ChapterName { get; set; }
        public virtual List<ChapterTnImage> ChapterImage { get; set; }
        public virtual List<SectionTn> Sections { get; set; }

        // FK
        public virtual CourseTn CourseTn { get; set; }
        public int CourseTnId { get; set; }
    }

You can additionally force FK recognition with attribute on CourseTnId in your ChapterTn class.
[ForeignKey("CourseTn"), Column(Order = 0)]

You planned to design a one-to-many relationship between Course and Chapter : every Course has zero or more Chapters , every Chapter belongs to exactly one Course .

For some reason you decided to deviate from the entity framework code-first conventions , thus obliging you to correct this using attributes or fluent API.

Why are your "to-many" collection classes Lists instead of ICollections? Does Course.Chapters[4] really mean something? Besides, are you sure that you want to limit yourself to Courses with real Lists of Chapters? No of course not, because internally your Course does not even have a List of chapters. Internally there are two tables with foreign keys and such. So it isn't a List. It is at utmost a thing where you can Add an element, and can ask for the number of Elements: not a List, but an ICollection.

For some reason the type of the primary key of your Courses is a CourseLevel. Are you sure that in your design it is unthinkable that two Courses might have the same CourseLevel? And are you sure, that before adding a Course to your database you don't know its CourseLevel? Will a Course never get harder or easier, and thus changes its CourseLevel? What benefit did you get by trying to do some tricky things with the database identifiers?

Furthermore, and I think that is the cause of your problem: although you give your chapters a value CourseId you forget to tell entity framework that this is the foreign key to the Course of the chapter.

The following is really enough to solve all your problems.

class Course
{
    public int Id {get; set;}
    // every Course has zero or more Chapters:
    public virtual ICollection<Chapter> Chapters {get; set;}

    // other properties:
    public CourseLevel Level {get; set;}
    ...
}

class Chapter
{
    public int Id {get; set;}

    // every Chapter belongs to exactly one Course using foreign key
    public int CourseId {get; set;}
    public virtual Course Course {get; set;}

    ... // other properties
}

Because I followed the entity framework one-to-many conventions , this is all entity framework needs to know to configure the two tables and the primary and foreign key. No attributes, nor fluent API is needed.

I also changed the primary key to a more conventional type, if you really have good arguments to keep it your way, try it and see if it works.

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