From 9792dbd26d2c238a4480154c368167000471cb15 Mon Sep 17 00:00:00 2001 From: lajones Date: Fri, 10 Jul 2020 17:29:38 -0700 Subject: [PATCH] Add API to allow configuration of the association entity type. --- .../Builders/CollectionCollectionBuilder.cs | 19 +++ .../Migrations/ModelSnapshotSqlServerTest.cs | 132 ++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/src/EFCore/Metadata/Builders/CollectionCollectionBuilder.cs b/src/EFCore/Metadata/Builders/CollectionCollectionBuilder.cs index e8a11ceb312..f8fecfc10cc 100644 --- a/src/EFCore/Metadata/Builders/CollectionCollectionBuilder.cs +++ b/src/EFCore/Metadata/Builders/CollectionCollectionBuilder.cs @@ -83,6 +83,25 @@ public CollectionCollectionBuilder( [EntityFrameworkInternal] protected virtual InternalModelBuilder ModelBuilder => LeftEntityType.AsEntityType().Model.Builder; + /// + /// Configures the association entity type implementing the many-to-many relationship. + /// + /// The configuration of the association type. + /// The builder for the originating entity type so that multiple configuration calls can be chained. + public virtual EntityTypeBuilder UsingEntity( + [NotNull] Action configureAssociation) + { + Check.DebugAssert(LeftNavigation.AssociationEntityType != null, "LeftNavigation.AssociationEntityType is null"); + Check.DebugAssert(RightNavigation.AssociationEntityType != null, "RightNavigation.AssociationEntityType is null"); + Check.DebugAssert(LeftNavigation.AssociationEntityType == RightNavigation.AssociationEntityType, + "LeftNavigation.AssociationEntityType != RightNavigation.AssociationEntityType"); + + var associationEntityTypeBuilder = new EntityTypeBuilder(LeftNavigation.AssociationEntityType); + configureAssociation(associationEntityTypeBuilder); + + return new EntityTypeBuilder(RightEntityType); + } + /// /// Configures the relationships to the entity types participating in the many-to-many relationship. /// diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs index 0b1f1ade01b..9c90c8be529 100644 --- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs +++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs @@ -1238,6 +1238,138 @@ public virtual void Many_to_many_join_table_stored_in_snapshot() }); } + + [ConditionalFact] + public virtual void Can_override_table_name_for_many_to_many_join_table_stored_in_snapshot() + { + Test( + builder => + { + var manyToMany = builder + .Entity() + .HasMany(l => l.Rights) + .WithMany(r => r.Lefts) + .UsingEntity(a => a.ToTable("MyJoinTable")); + }, + AddBoilerPlate( + GetHeading() + + @" + modelBuilder.Entity(""ManyToManyLeftManyToManyRight"", b => + { + b.Property(""ManyToManyLeft_Id"") + .HasColumnType(""int""); + + b.Property(""ManyToManyRight_Id"") + .HasColumnType(""int""); + + b.HasKey(""ManyToManyLeft_Id"", ""ManyToManyRight_Id""); + + b.HasIndex(""ManyToManyRight_Id""); + + b.ToTable(""MyJoinTable""); + }); + + modelBuilder.Entity(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyLeft"", b => + { + b.Property(""Id"") + .ValueGeneratedOnAdd() + .HasColumnType(""int"") + .UseIdentityColumn(); + + b.Property(""Name"") + .HasColumnType(""nvarchar(max)""); + + b.HasKey(""Id""); + + b.ToTable(""ManyToManyLeft""); + }); + + modelBuilder.Entity(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyRight"", b => + { + b.Property(""Id"") + .ValueGeneratedOnAdd() + .HasColumnType(""int"") + .UseIdentityColumn(); + + b.Property(""Description"") + .HasColumnType(""nvarchar(max)""); + + b.HasKey(""Id""); + + b.ToTable(""ManyToManyRight""); + }); + + modelBuilder.Entity(""ManyToManyLeftManyToManyRight"", b => + { + b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyLeft"", null) + .WithMany() + .HasForeignKey(""ManyToManyLeft_Id"") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyRight"", null) + .WithMany() + .HasForeignKey(""ManyToManyRight_Id"") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + });", usingSystem: true), + model => + { + var associationEntity = model.FindEntityType("ManyToManyLeftManyToManyRight"); + Assert.NotNull(associationEntity); + Assert.Equal("MyJoinTable", associationEntity.GetTableName()); + Assert.Collection(associationEntity.GetDeclaredProperties(), + p => + { + Assert.Equal("ManyToManyLeft_Id", p.Name); + Assert.True(p.IsShadowProperty()); + }, + p => + { + Assert.Equal("ManyToManyRight_Id", p.Name); + Assert.True(p.IsShadowProperty()); + }); + Assert.Collection(associationEntity.FindDeclaredPrimaryKey().Properties, + p => + { + Assert.Equal("ManyToManyLeft_Id", p.Name); + }, + p => + { + Assert.Equal("ManyToManyRight_Id", p.Name); + }); + Assert.Collection(associationEntity.GetDeclaredForeignKeys(), + fk => + { + Assert.Equal("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyLeft", fk.PrincipalEntityType.Name); + Assert.Collection(fk.PrincipalKey.Properties, + p => + { + Assert.Equal("Id", p.Name); + }); + Assert.Collection(fk.Properties, + p => + { + Assert.Equal("ManyToManyLeft_Id", p.Name); + }); + }, + fk => + { + Assert.Equal("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyRight", fk.PrincipalEntityType.Name); + Assert.Collection(fk.PrincipalKey.Properties, + p => + { + Assert.Equal("Id", p.Name); + }); + Assert.Collection(fk.Properties, + p => + { + Assert.Equal("ManyToManyRight_Id", p.Name); + }); + }); + }); + } + [ConditionalFact] public virtual void TableName_preserved_when_generic() {