foreign-keysentity-framework-corecode-firstgrandchild

I want no Parent entity or foreign key on the Grandchild entity


I have three entities, BaseEntity, Child and GrandChild, that are predictably linked together.

It goes like this:

    public class BaseEntity
    {
        public string CompanyId { get; set; }

        public string BaseEntityId { get; set; }

        public virtual List<Child> Children { get; set; }
    }

    public class Child
    {
        public string CompanyId { get; set; }

        public string BaseEntityId { get; set; }

        public string ChildId { get; set; }

        public virtual BaseEntity Parent { get; set; }

        public virtual List<GrandChild> GrandChildren { get; set; }
    }

    public class GrandChild
    {
        public string CompanyId { get; set; }

        public string BaseEntityId { get; set; }

        public string ChildId { get; set; }

        public string GrandChildId { get; set; }

        public virtual Child ParentChild { get; set; }
    }

    public class BaseContext : DbContext
    {
        protected override void OnModelCreating(ModelBuilder p_mbuModel)
        {
            p_mbuModel.Entity<BaseEntity>().ToTable("T_BaseEntity");

            p_mbuModel.Entity<BaseEntity>().HasKey(t => new { t.CompanyId, t.BaseEntityId });

            p_mbuModel.Entity<Child>().ToTable("T_Child");

            p_mbuModel.Entity<Child>().HasKey(t => new { t.CompanyId, t.BaseEntityId, t.ChildId });

            p_mbuModel.Entity<Child>().HasOne(c => c.Parent).
                                       WithMany(p => p.Children).
                                       HasForeignKey(c => new { c.CompanyId, c.BaseEntityId }).
                                       HasConstraintName("FK_Child_BaseEntity");

            p_mbuModel.Entity<GrandChild>().ToTable("T_GrandChild");

            p_mbuModel.Entity<GrandChild>().HasKey(t => new { t.CompanyId, t.BaseEntityId, t.ChildId, t.GrandChildId });

            p_mbuModel.Entity<GrandChild>().HasOne(gc => gc.ParentChild).
                                            WithMany(c => c.GrandChildren).
                                            HasForeignKey(gc => new { gc.CompanyId, gc.BaseEntityId, gc.ChildId }).
                                            HasConstraintName("FK_GrandChild_Child");
        }
    }

You'll note that it features no direct link from GrandChild to BaseEntity and no foreign key between GrandChild and BaseEntity. Which is consistent. I don't want that direct link. (If nothing else, it could lead to unpleasantness with cascading deletions.)

Still, when I launch Add-Migration, I get the following:

    table.ForeignKey(
        name: "FK_T_GrandChild_T_BaseEntity_BaseEntityId",
                        columns: x => { x.CompanyId, x.BaseEntityId },
                        principalTable: "T_BaseEntity",
                        principalColumns: new { "CompanyId", "BaseEntityId" },
                        onDelete: ReferentialAction.Cascade);

The very thing that I have tried to keep out. (On migrating, it creates the foreign key constraint that I don't want, and with that unwieldy name to boot.)

I have tried adding

    p_mbuModel.Entity<GrandChild>().Ignore(t => new { t.CompanyId, t.BaseEntityId });

which raises an exception to the tune of

The expression 't => new <>f__AnonymousType10`2(CompanyId = t.CompanyId, BaseEntityId = t.BaseEntityId)' is not a valid property expression. The expression should represent a simple property access: 't => t.MyProperty'.

(I guess that's to be expected; that was a long shot on my behalf.)

I could add a GrandParent property to GrandChild and use Ignore() on it, but that would require me to create the very link I want to hide.

I want no link between BaseEntity and GrandChild, neither as entities nor as database tables.

How can I achieve this?


Solution

  • ... I'm embarrassed to admit this. When I posted the question, I trimmed the irrelevant parts of my classes. And I didn't notice that BaseEntity included this line:

            public virtual List<GrandChild> GrandChildren { get; set; }
    

    I removed it and launched Add-Migration again. No link appeared between BaseEntity and GrandChild.

    Apologies to any and all who tried to make sense of this incomplete riddle.