dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.79k stars 3.19k forks source link

code first migrations in ef core with more than one one to one relationship between the same entities only adds one relationship #16283

Closed vsfeedback closed 2 years ago

vsfeedback commented 5 years ago

Configuring two one to one relationships only creates the second relationship as can be verified by looking at SQL Object Explorer.

The first relationship is configured using RoleClaimBase as Foreign Key table and the code

builder. HasOne(p => p.ClaimBase)
               . WithOne(p => p.RoleClaimBase)
               . HasForeignKey<RoleClaimBase>(p => new { p.TenantId, p.ClaimId })
               . HasPrincipalKey<ClaimBase>(p => new { p.TenantId, p.ClaimId })
               . HasConstraintName("FK_RoleClaimBase___ClaimBase___TenantId_ClaimId");

The second relationship is configured using RoleClaimBase as Foreign key table and the code

builder. HasOne(p => p.ClaimBase)
          . WithOne(p => p.RoleClaimBase)
          . HasForeignKey<RoleClaimBase>(p => new { p.TenantId, p.ClaimName })
          . HasPrincipalKey<ClaimBase>(p => new { p.TenantId, p.ClaimName })
         . HasConstraintName("FK_RoleClaimBase___ClaimBase___TenantId_ClaimName");

What happens is that if one or the other block of code is commented out then migrations using add-migration and update-database command correctly creates the one to one relationship. However if both blocks of code are included then instead of creating two one to own relationships only the second one to one relationship is created in the database. The code below shows the class where the code is included. If necessary I can provide a simpler example.

using FOF_IN_CLOUD. MultiTenantSpecialization.IdentityUser.Classes;
using IdentityMultiTenantDbContext.MultiTenantSpecialization.IdentityUser.Classes;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace IdentityMultiTenantDbContext.ContextClasses
{
    public class RoleClaimBaseConfiguration
   : IEntityTypeConfiguration<RoleClaimBase>
    {

public void Configure(EntityTypeBuilder<RoleClaimBase> builder)
        {
            builder. ToTable("RoleClaimBase", "MultiTenantUser");

builder. Property(p => p.ClaimName). IsRequired();

builder. HasKey(p => new { p.TenantId, p.RoleId, p.ClaimId })
                . HasName("PK_RoleClaimBase___TenantId_RoleId_ClaimId");

builder. HasAlternateKey(p => new { p.TenantId, p.ClaimId })
                . HasName("AK_RoleClaimBase___TenantId_ClaimId");

builder. HasAlternateKey(p => new { p.TenantId, p.ClaimName })
                . HasName("AK_RoleClaimBase___TenantId_ClaimName");

builder. HasOne(p => p.Role)
                . WithMany(p => p.RoleClaimBaseCollection)
                . HasForeignKey(p => new { p.TenantId, p.RoleId })
                . HasPrincipalKey(p => new { p.TenantId, p.RoleId })
                . HasConstraintName("FK_RoleClaimBase___Role___TenantId_RoleId");

/* Configure a one to one relationship (strictly one to at most one) between tables ClaimBase
             * and RoleClaimBase with ClaimBase being the Principal Key table (or Referenced table)
             * and RoleClaimBase being the Foreign Key table and  The keys are matching on { TenantId, ClaimId}.
             */
            builder. HasOne(p => p.ClaimBase)
               . WithOne(p => p.RoleClaimBase)
               . HasForeignKey<RoleClaimBase>(p => new { p.TenantId, p.ClaimId })
               . HasPrincipalKey<ClaimBase>(p => new { p.TenantId, p.ClaimId })
               . HasConstraintName("FK_RoleClaimBase___ClaimBase___TenantId_ClaimId");
            /* Configure a one to one relationship (strictly one to at most one) between tables ClaimBase
            * and RoleClaimBase with ClaimBase being the Principal Key table (or Referenced table)
            * and RoleClaimBase being the Foreign Key table and  The keys are matching on { TenantId, ClaimName}.
            */
            builder. HasOne(p => p.ClaimBase)
              . WithOne(p => p.RoleClaimBase)
              . HasForeignKey<RoleClaimBase>(p => new { p.TenantId, p.ClaimName })
              . HasPrincipalKey<ClaimBase>(p => new { p.TenantId, p.ClaimName })
             . HasConstraintName("FK_RoleClaimBase___ClaimBase___TenantId_ClaimName");

builder. OwnsOne<ClaimData>(p=>p.ClaimData);
        }
    }
}

This issue has been moved from https://developercommunity.visualstudio.com/content/problem/586849/code-first-migrations-in-ef-core-with-more-than-on.html VSTS ticketId: 900931 These are the original issue comments:

Visual Studio Feedback System on 5/29/2019, 00:23 AM (27 days ago):

We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.

These are the original issue solutions: (no solutions)

ajcvickers commented 5 years ago

Duplicate of #16278