简体   繁体   中英

Entity Framework - Botched association

I am attempting to create "code first from database" classes using Entity Framework 6.1.3 but it seems EF is having trouble making associations (or I am simply not setting something up correctly in my database).

Here are the two tables in question, I am making classes from using entity framework;

数据库架构

In my database CVE has a one-to-many relationship with AssessmentChecks. Thus the AssessmentChecks table has a foreign key in it as such;

ALTER TABLE NVD.[AssessmentChecks] ADD CONSTRAINT
    FK_AssessmentChecks_CVE FOREIGN KEY
    (
    CveIDFK
    ) REFERENCES NVD.CVE
    (
    CveID
    ) ON UPDATE  NO ACTION 
     ON DELETE  NO ACTION 

However, when I create classes from this database, Entity Framework is marking "CveIDFK" as a required field...

public partial class AssessmentCheck
{
    public int AssessmentCheckID { get; set; }

    [Required]
    [StringLength(20)]
    public string CveIDFK { get; set; }

    public string AssessmentCheckSystem { get; set; }

    public string AssessmentCheckURL { get; set; }

    [StringLength(200)]
    public string AssessmentCheckName { get; set; }

    public virtual CVE CVE { get; set; }
}

If I use that same database to instead create an EDMX file (EF designer, instead of "Code First"), here is what that model diagram and AssessmentCheck class look like (which is more of what I was expecting);

CVE评估检查NVD数据库

public partial class AssessmentCheck
{
    public int AssessmentCheckID { get; set; }
    public string CveID { get; set; }
    public string AssessmentCheckSystem { get; set; }
    public string AssessmentCheckURL { get; set; }
    public string AssessmentCheckName { get; set; }

    public virtual CVE CVE { get; set; }
}

What gives? How can I make Entity Framework create the association in the code first model, so that "CveIDFK" is not "Required"?

To be clear, my end goal is to create classes from the database, create a "CVE" object, add an "AssessmentCheck" to the "CVE" object, and then "SaveChanges". The problem is when I do this, and try to Save Changes, EF is saying I need to explicitly provide the "CveIDFK" field of the "AssessmentCheck" object. I believe this FK should be automatically implied given the relationship between CVE and AssessmentChecks. Am I missing something?


EDIT:

I updated the database to go back to using CveID" as the name of the foreign key in the AssessmentChecks table, and recreated my classes.

Here is the code I am using to try to save the data;

CVE cve = new CVE
            {
                CveID = "CVE-2016-2140"
            };

            AssessmentCheck AC1 = new AssessmentCheck
            {
                AssessmentCheckName = "First Assessment check"
            };

            AssessmentCheck AC2 = new AssessmentCheck
            {
                AssessmentCheckName = "Second Assessment Check"
            };

            cve.AssessmentChecks.Add(AC1);
            cve.AssessmentChecks.Add(AC2);

            using (var context = new NVDModel())
            {
                try
                {
                    context.Database.Log = Console.WriteLine;
                    context.CVEs.Add(cve);       
                    context.SaveChanges();
                }
            }

And the error I get is

Entity of type "AssessmentCheck" in state "Added" has the following validation e rrors: - Property: "CveID", Error: "The CveID field is required." Entity of type "AssessmentCheck" in state "Added" has the following validation e rrors: - Property: "CveID", Error: "The CveID field is required."

If I remove the "required" data annotation from the "CveID" field of the "AssessmentChecks" class, it works (the foreign key is automatically inserted without me explicitly providing it), but I wouldnt think I have to remove this data annotation.

Also, if I move the addition of the children after I add the parent to the context, that also works;

try
                {
                    context.Database.Log = Console.WriteLine;
                    context.CVEs.Add(cve);
                    cve.AssessmentChecks.Add(AC1);
                    cve.AssessmentChecks.Add(AC2);
                    context.SaveChanges();
                }

What is going on here?

Once you add the entity into dbset(CVEs in your case) entity framework start tracking any changes made to it hence when you add the child object(AssessmentCheck) into this entity it is able to assign the parent id through the information provided by you ie data annotation in case of code first. Hence the second second method is working.

In first method you will be able to achieve the same if instead of providing the PK(CveId) for CVE you were using the identity ie auto generated, but since you are using string as PK in CVE identity is not possible, one simple solution is have int as PK and make the existing CveId a unique key, otherwise use a custom add instead of cve.AssessmentChecks.Add... which assign/set the FK to children.

You can see this action if you use the following method before save changes

var entitychanges = context.ChangeTracker.Entries().Where(e => e.State == EntityState.Added);

you will notice in first method CveID is not set for AssessmentCheck while in second it is.

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