EF Core not saving ParentId

c# entity-framework-core

Question

I am trying to build up a structure of 'Job' objects. These are used to describe an entire process a person would need to do.

For example.

If the Job had the description "Make Coffee", it would have a List of other jobs that when done all together result in making a coffee.

An example structure might be:

Make Coffee
  |- Boil Kettle
     |- Fill Kettle
     |- Turn on Kettle
  |- Get a cup
  |- Place instant coffee in the cup
  |- Pour boiling water in the cup
  |- Add milk to the cup

It should also be noted, each Job has a version number; and VersionOfID. This is in case a job needs to be changed, only one version is 'Live' and is the one that will be used.

I am adding objects to the EF Core DBContext, and before I call SaveChanges, I can see the structure correctly; However, once the context is closed/reloaded the jobs no longer reference each other. I can see in SQL Management studio the ParentID is null for all the objects.

The class for Job is as follows:

public class Job
{
    public int JobId { get; set; }

    [Required]
    public string Description { get; set; }

    public string Code { get; set; }

    public int Quantity { get; set; } = 1;

    public int Time { get; set; }

    public TimeUnit UnitOfTime { get; set; }

    [ForeignKey("VersionOf")]
    public int? VersionOfId { get; set; }
    public virtual Job VersionOf { get; set; }

    public int JobVersion { get; set; } = 1;

    [ForeignKey("Parent")]
    public int? ParentId { get; set; }
    public virtual Job Parent { get; set; }

    public virtual List<Job> Jobs { get; set; } = new List<Job>();

    public void AddJob(Job job)
    {
        job.Parent = this;
        Jobs.Add(job);
    }
}

public enum TimeUnit
{
    Seconds,
    Minutes,
    Hours,
    Days,
    Weeks,
    Months,
    Years
} 

I am adding them to the context like this:

        DatabaseContext dbContext = new DatabaseContext();

        Job PK3 = new Job()
        {
            Code = "PK3",
            Description = "Scan Item",
            Time = 7,
            UnitOfTime = TimeUnit.Seconds,
        };
        dbContext.Jobs.Add(PK3);

        Job PK4 = new Job()
        {
            Code = "PK4",
            Description = "Pick Item",
            Time = 15,
            UnitOfTime = TimeUnit.Seconds,
        };
        dbContext.Jobs.Add(PK4);

        Job PK5 = new Job()
        {
            Code = "PK5",
            Description = "Walk To Item",
            Time = 60,
            UnitOfTime = TimeUnit.Seconds,
        };
        dbContext.Jobs.Add(PK5);

        Job OP1 = new Job()
        {
            Code = "OP1",
            Description = "Entire Item Pick",
            Quantity = 1,
        };

        OP1.AddJob(PK5);
        OP1.AddJob(PK4);
        OP1.AddJob(PK3);

        dbContext.Jobs.Add(OP1);

        try
        {
            int a =  dbContext.SaveChanges();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }

You can see how the table looks here: table with NULL IDs

I thought it might be todo with LazyLoading, which I have enabled with:

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"<--snip-->");
        optionsBuilder.UseLazyLoadingProxies();
    }

However, I have removed this and this issue continues.

Does anyone know how to fix this?

1
0
7/31/2018 9:39:11 PM

Accepted Answer

@David Browne - Microsoft is correct, the issue was EF Core simply didn't know how to handle both Foreign Keys. Adding the following to my OnModelCreating has resolved this issue for me.

I'm not sure if this is the 'Correct' way to do it, but it works for me.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Job>().HasOne(j => j.Parent);
    modelBuilder.Entity<Job>().HasOne(j => j.VersionOf);
}
0
7/31/2018 9:41:02 PM

Popular Answer

You are missing the assignment of Parent

Job PK4 = new Job()
{
    Code = "PK4",
    Description = "Pick Item",
    Time = 15,
    UnitOfTime = TimeUnit.Seconds,
    Parent = PK3 //add this line!
};


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow