1
votes

I'm trying to correct the relationship below. For some reason, the primary key set on the ChildClass used a composite of the ParentClassId and the ChildClassId when it should have just used the ChildClassId.

public partial class ParentClass
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ParentClassId { get; set; }

    public DateTime SomeDate { get; set; }

    public string SomeString { get; set; }

    public virtual ICollection<ChildClass> ChildClasses { get; set; }
}

public partial class ChildClass
{
    [Key, ForeignKey("ParentClass"), Column(Order = 1)]
    public int ParentClassId { get; set; }
    [Key, Column(Order = 2)]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ChildClassId { get; set; }

    public virtual ParentClass ParentClass { get; set; }

    public DateTime SomeDate { get; set; }

    public string SomeString { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        modelBuilder.Entity<ParentClass>()
            .HasMany(e => e.ChildClasses)
            .WithRequired(e => e.ParentClass);
}

Thus far I have:

public partial class ParentClass
{
    public int ParentClassId { get; set; }

    public DateTime SomeDate { get; set; }

    public string SomeString { get; set; }

    public virtual ICollection<ChildClass> ChildClasses { get; set; }
}

public partial class ChildClass
{
    public int ChildClassId { get; set; }
    public int ParentClassId { get; set; }

    public virtual ParentClass ParentClass { get; set; }

    public DateTime SomeDate { get; set; }

    public string SomeString { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        modelBuilder.Entity<ParentClass>()
            .HasMany(e => e.ChildClasses)
            .WithRequired(e => e.ParentClass);
}

This provides a migration script which just drops and recreates the primary key as expected.

Now, when I load a parent, clear the Child objects and recreate them and then try to save the changes

ParentClass p = await db.ParentClasses.Include("ChildClasses").SingleOrDefaultAsync(r => r.ParentClassId == 1).ConfigureAwait(false);
p.ChildClasses.Clear();

ChildClass c = new ChildClass { SomeDate = DateTime.Now, SomeString="some string" };
p.ChildClasses.Add(c);

await db.SaveChangesAsync().ConfigureAwait(false); //<< Error on this

I get the error:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

The tables and associated keys, indexes etc look fine. The SaveChanges line doesn't get as far as the database so somewhere in the model (not visible to me) it seems to be not respecting the updated relationship.

EDIT: based on reading around I've also tried iterating through as per below and get the same error.

foreach (ChildClass t in p.ChildClasses.ToList()) p.ChildClasses.Remove(t);

What am I missing?

1
What you want when you are doing p.ChildClasses.Clear(); ?Dilshod K
Does p.ChildClasses.Clear() actually delete the child classes? The error you get sounds like it’s trying to save the child classes only now without a ParentId.Neil.Work
Just to clarify, the p.ChildClasses.Clear(); is existing code which was working until I changed the relationship.mattpm
@mattpm, I think, Remove() also does the same as Clear(). Try remove it using context. Like db.Remove(t)Dilshod K
@DIlshod - cheers. The EF version I'm using doesn't appear to have a db.Remove(t) method. However, based on your suggestion I have tried using db.ChildClasses.RemoveRange(p.ChildClasses.ToList()); instead and that has removed the child objects. Will pick this up again Monday.mattpm

1 Answers

3
votes

Clear() method will not delete entities in ChildClasses collection. If you think that ChildClass can be without ParentClass you should make foreign key as nullable

public int? ParentClassId { get; set; } then it should work