Issue with Entity Framework TPT hierarchy and relationships

186 views Asked by At

my current EF6 implementation goes somewhat like this:

    public class Parent
    {
        public int Id { get; set; }
        public virtual string Name { get; set; }
        public string Description { get; set; }
        public virtual ICollection Children { get; set; }

        public int OtherEntityId { get; set; }
        public virtual OtherEntity OtherEntity { get; set; }
    }

    public class Child : Parent
    {
        public int Id { get; set; }
        public override string Name 
        { 
            get { return Parent == null ? "Dummy" : Parent.Name; }
        }
        public string Description { get; set; }
        public ParentId { get; set; }
        public virtual Parent { get; set; }

        public override int OtherEntityId
        {
            get { return Parent == null ? default(int) : Parent.OtherEntityId; }
        }
    }

The fluent configuration for the Child goes like this:

    this.ToTable("Child")
        .HasRequired(x => x.Parent)
        .WithMany(x => x.Children)
        .HasForeignKey(xy => xy.ParentId);

The idea is to have one entry for every Parent and Child in my Parent table. Yet, the Child entity should not have a name of its own, but get the name from it's parent. I also need a way to navigate from every child to its parent. And I also need a way to navigate from every parent to its children. This only goes over 1 level.

The reason for this implementation was due to the requirement to always get certain values from the parent, yet the Child must have the same public interface as the Parent. Keep in mind that I can't change the Parent here, it is part of a framework I have to stick with. So only the child is actually part of my implementation.

The problem seems to be with the change tracking. If I query for a Child, EF loads the Child first, checks all properties, and loads the Parent second. Since now the name is different, for EF the name property already changed, even though I have not changed it manually.

The solution works somewhat, as long as I load the all entities without tracking. The moment I try to load them with tracking enabled I get an exception:

A referential integrity constraint violation occurred: A primary key property that is a part of referential integrity constraint cannot be changed when the dependent object is Unchanged unless it is being set to the association's principal object. The principal object must be tracked and not marked for deletion.

Same happens if a try to attach the entity after loading, and set its state to Unchanged. I do not change primary keys, or any keys at all, so it is not clear to me, why this error happens. It seems that the error happens during the relationship fixup. I fear its the "OtherEntityId" but I can't verify it, since I have no idea how to debug it. Anyone has ideas what the problem might be or how I can debug that properly?

I tried to get the internal values with something like: https://www.exceptionnotfound.net/entity-change-tracking-using-dbcontext-in-entity-framework-6/ But

ChangeTracker.Entries().Where(p => p.State == EntityState.Modified).ToList();

also seams to force a relationship fixup which leads to the error.

0

There are 0 answers