Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicate Foreign Key Constraints created in Migrations with TPH inheritance #5769

Closed
csmith93 opened this issue Jun 14, 2016 · 5 comments
Closed
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@csmith93
Copy link

csmith93 commented Jun 14, 2016

Steps to reproduce

public abstract class Schedule
{
    public Guid Id { get; set; }
    //...
}

public class EmployeeSchedule : Schedule
{
    public User Owner { get; set; }
    //...
}

public class ManagerSchedule : Schedule
{
    public Manager Owner { get; set; }
    //...
}

public abstract class User
{
    public Guid Id { get; set; }
    //...
}

public class Employee : User 
{
    //...
}
public class Manager : User
{
    //...
}

The issue

Within the generated migration:

        migrationBuilder.CreateTable(
            name: "Schedules",
            columns: table => new
            {
                Id = table.Column<Guid>(nullable: false),
                OwnerId = table.Column<Guid>(nullable: true),
                //...
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Schedules", x => x.Id);
                table.ForeignKey(
                    name: "FK_Schedules_Users_OwnerId",
                    column: x => x.OwnerId,
                    principalTable: "Users",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_Schedules_Users_OwnerId",
                    column: x => x.OwnerId,
                    principalTable: "Users",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
                //...

Further technical details

EF Core version: 1.0.0-rc2-final
Operating system: Win 7 x64
Visual Studio version: VS 2015 Update 2

@csmith93
Copy link
Author

Possibly related to #5665

@csmith93 csmith93 changed the title Duplicate Foreign Key Constraints created with TPH Duplicate Foreign Key Constraints created in Migrations with TPH Jun 14, 2016
@csmith93 csmith93 changed the title Duplicate Foreign Key Constraints created in Migrations with TPH Duplicate Foreign Key Constraints created in Migrations with TPH inheritance Jun 14, 2016
@rowanmiller rowanmiller added this to the 1.1.0 milestone Jun 15, 2016
@rowanmiller rowanmiller removed the pri0 label Jul 6, 2016
AndriySvyryd added a commit that referenced this issue Jul 22, 2016
Validate that matching foreign keys and indexes are compatible

Fixes #5769
AndriySvyryd added a commit that referenced this issue Jul 22, 2016
Validate that matching foreign keys and indexes are compatible

Fixes #5769
AndriySvyryd added a commit that referenced this issue Jul 26, 2016
Validate that matching foreign keys and indexes are compatible

Fixes #5769
@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jul 26, 2016
@csmith93
Copy link
Author

@AndriySvyryd Thanks for figuring this out!

@Sojaner
Copy link

Sojaner commented Sep 15, 2016

I am facing another similar but different problem @rowanmiller @AndriySvyryd

Steps to reproduce
Consider these View Models:

public abstract class PersonBaseViewModel
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string IdNumber { get; set; }

    public virtual CityViewModel CityVM { get; set; }
}

public abstract class ServicePersonViewModel: PersonBaseViewModel
{
    public string PersonnelNumber { get; set; }
}

public class CitizenViewModel : PersonBaseViewModel
{
    //...
}

public class PoliceViewModel : ServicePersonViewModel
{
    //...
}

public class CityViewModel
{
    public int Id { get; set; }

    public ICollection<Citizen> People { get; set; }
    public ICollection<Police> Securities { get; set; }
}

The migrations being generated include codes similar to these:

modelBuilder.Entity("PersonBaseViewModel", b =>
{
   //...

   b.Property<int?>("CityVMId");

   //...

   b.HasIndex("CityVMId");

   //...
});

modelBuilder.Entity("CitizenViewModel", b =>
{
   b.HasBaseType("PersonBaseViewModel");

   //...

   b.Property<int?>("CityViewModelId");

   //...

   b.HasIndex("CityViewModelId");

   //...
 });

modelBuilder.Entity("PoliceViewModel", b =>
{
   b.HasBaseType("ServicePersonViewModel");

   //...

   b.Property<int?>("CityViewModelId");

   //...

   b.HasIndex("CityViewModelId");

   //...
 });

 //--------------------------------------------------

modelBuilder.Entity("PersonBaseViewModel", b =>
{
   b.HasOne("CityViewModel", "CityVM")
    .WithMany()
    .HasForeignKey("CityVMId");
});

modelBuilder.Entity("CitizenViewModel", b =>
{
   b.HasOne("CityViewModel", "CityVM")
    .WithMany()
    .HasForeignKey("CityViewModelId");
});

modelBuilder.Entity("PoliceViewModel", b =>
{
   b.HasOne("CityViewModel", "CityVM")
    .WithMany()
    .HasForeignKey("CityViewModelId");
});

//--------------------------------------------------

migrationBuilder.CreateTable(
name: "PersonBases",
columns: table => new
{
    //...

       CityVMId = table.Column<int>(nullable: true),

    //...

    CityViewModelId = table.Column<int>(nullable: true),

    //...
},
constraints: table =>
{
    table.PrimaryKey("PK_PersonBases", x => x.Id);
    table.ForeignKey(
        name: "FK_PersonBases_Cities_CityVMId",
        column: x => x.CityVMId,
        principalTable: "Cities",
        principalColumn: "Id",
        onDelete: ReferentialAction.Restrict);
    table.ForeignKey(
        name: "FK_PersonBases_Cities_CityViewModelId",
        column: x => x.CityViewModelId,
        principalTable: "Cities",
        principalColumn: "Id",
        onDelete: ReferentialAction.Restrict);
});

The issue
As you can see, there are two different foreign keys being generated between Cities and PersonBases tables, however the CityVMId column is always empty and contains NULLs.

Removing the extra foreign key from migrations fixes the database creation, however when inserting data into the table using EF Core, an exception with message 'Column CityVMId could not be found' (Or something similar) is being raised.

Therefore, an empty column for CityVMId must be existing in the database for the EF Core to work when inserting/updating data.

Concerns
I think this should be fixed as soon as possible not be postponed for version 1.1.0, because the database created this way has structure issues and if filled with data over time, it will be difficult to be altered later when version 1.1,0 is released and the problem is solved.

Further technical details
Dot Net Core version: 1.0.1 (1.0.0-preview2-003131/DotNetCore.1.0.1-VS2015Tools.Preview2.0.2)
Entity Framework Core version: 1.0.1 (1.0.0-preview2-21431)
Operating system: Windows 10 x64
Visual Studio version: VS 2015 Update 3

@AndriySvyryd
Copy link
Member

@Sojaner The issue you are seeing is not related, could you open a new issue with this info?
It looks like EF doesn't match correctly the inherited CityVM navigation with the inverses People and Securities and creates 3 relationships.
As a workaround you would need to configure the relationships explicitly:

modelBuilder.Entity<CitizenViewModel>().HasOne(c => c.CityVM).WithMany(c => c.People);
modelBuilder.Entity<PoliceViewModel>() .HasOne(p => p.CityVM).WithMany(c => c.Securities);

@Sojaner
Copy link

Sojaner commented Sep 16, 2016

Thanks for the workaround @AndriySvyryd
I have created the issue #6554 for this problem now.

@ajcvickers ajcvickers modified the milestones: 1.1.0-preview1, 1.1.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

5 participants